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 21 import org.springframework.web.bind.annotation.*;
22 22 import org.thingsboard.server.common.data.Customer;
23 23 import org.thingsboard.server.common.data.asset.Asset;
  24 +import org.thingsboard.server.common.data.asset.TenantAssetType;
24 25 import org.thingsboard.server.common.data.id.AssetId;
25 26 import org.thingsboard.server.common.data.id.CustomerId;
26 27 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -136,13 +137,18 @@ public class AssetController extends BaseController {
136 137 @ResponseBody
137 138 public TextPageData<Asset> getTenantAssets(
138 139 @RequestParam int limit,
  140 + @RequestParam(required = false) String type,
139 141 @RequestParam(required = false) String textSearch,
140 142 @RequestParam(required = false) String idOffset,
141 143 @RequestParam(required = false) String textOffset) throws ThingsboardException {
142 144 try {
143 145 TenantId tenantId = getCurrentUser().getTenantId();
144 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 152 } catch (Exception e) {
147 153 throw handleException(e);
148 154 }
... ... @@ -167,6 +173,7 @@ public class AssetController extends BaseController {
167 173 public TextPageData<Asset> getCustomerAssets(
168 174 @PathVariable("customerId") String strCustomerId,
169 175 @RequestParam int limit,
  176 + @RequestParam(required = false) String type,
170 177 @RequestParam(required = false) String textSearch,
171 178 @RequestParam(required = false) String idOffset,
172 179 @RequestParam(required = false) String textOffset) throws ThingsboardException {
... ... @@ -176,7 +183,11 @@ public class AssetController extends BaseController {
176 183 CustomerId customerId = new CustomerId(toUUID(strCustomerId));
177 184 checkCustomerId(customerId);
178 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 191 } catch (Exception e) {
181 192 throw handleException(e);
182 193 }
... ... @@ -231,4 +242,18 @@ public class AssetController extends BaseController {
231 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 25 import org.springframework.web.bind.annotation.ExceptionHandler;
26 26 import org.thingsboard.server.actors.service.ActorService;
27 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 30 import org.thingsboard.server.common.data.asset.Asset;
29 31 import org.thingsboard.server.common.data.id.*;
30 32 import org.thingsboard.server.common.data.page.TextPageLink;
... ... @@ -36,6 +38,7 @@ import org.thingsboard.server.common.data.rule.RuleMetaData;
36 38 import org.thingsboard.server.common.data.security.Authority;
37 39 import org.thingsboard.server.common.data.widget.WidgetType;
38 40 import org.thingsboard.server.common.data.widget.WidgetsBundle;
  41 +import org.thingsboard.server.dao.alarm.AlarmService;
39 42 import org.thingsboard.server.dao.asset.AssetService;
40 43 import org.thingsboard.server.dao.customer.CustomerService;
41 44 import org.thingsboard.server.dao.dashboard.DashboardService;
... ... @@ -84,6 +87,9 @@ public abstract class BaseController {
84 87 protected AssetService assetService;
85 88
86 89 @Autowired
  90 + protected AlarmService alarmService;
  91 +
  92 + @Autowired
87 93 protected DeviceCredentialsService deviceCredentialsService;
88 94
89 95 @Autowired
... ... @@ -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 359 WidgetsBundle checkWidgetsBundleId(WidgetsBundleId widgetsBundleId, boolean modify) throws ThingsboardException {
338 360 try {
339 361 validateId(widgetsBundleId, "Incorrect widgetsBundleId " + widgetsBundleId);
... ...
... ... @@ -21,6 +21,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
21 21 import org.springframework.web.bind.annotation.*;
22 22 import org.thingsboard.server.common.data.Customer;
23 23 import org.thingsboard.server.common.data.Device;
  24 +import org.thingsboard.server.common.data.TenantDeviceType;
24 25 import org.thingsboard.server.common.data.id.CustomerId;
25 26 import org.thingsboard.server.common.data.id.DeviceId;
26 27 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -166,13 +167,18 @@ public class DeviceController extends BaseController {
166 167 @ResponseBody
167 168 public TextPageData<Device> getTenantDevices(
168 169 @RequestParam int limit,
  170 + @RequestParam(required = false) String type,
169 171 @RequestParam(required = false) String textSearch,
170 172 @RequestParam(required = false) String idOffset,
171 173 @RequestParam(required = false) String textOffset) throws ThingsboardException {
172 174 try {
173 175 TenantId tenantId = getCurrentUser().getTenantId();
174 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 182 } catch (Exception e) {
177 183 throw handleException(e);
178 184 }
... ... @@ -197,6 +203,7 @@ public class DeviceController extends BaseController {
197 203 public TextPageData<Device> getCustomerDevices(
198 204 @PathVariable("customerId") String strCustomerId,
199 205 @RequestParam int limit,
  206 + @RequestParam(required = false) String type,
200 207 @RequestParam(required = false) String textSearch,
201 208 @RequestParam(required = false) String idOffset,
202 209 @RequestParam(required = false) String textOffset) throws ThingsboardException {
... ... @@ -206,7 +213,11 @@ public class DeviceController extends BaseController {
206 213 CustomerId customerId = new CustomerId(toUUID(strCustomerId));
207 214 checkCustomerId(customerId);
208 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 221 } catch (Exception e) {
211 222 throw handleException(e);
212 223 }
... ... @@ -261,4 +272,19 @@ public class DeviceController extends BaseController {
261 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 21 import org.thingsboard.server.common.data.id.EntityId;
22 22 import org.thingsboard.server.common.data.id.EntityIdFactory;
23 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 26 import org.thingsboard.server.dao.relation.EntityRelationsQuery;
25 27 import org.thingsboard.server.exception.ThingsboardErrorCode;
26 28 import org.thingsboard.server.exception.ThingsboardException;
... ... @@ -32,7 +34,7 @@ import java.util.List;
32 34 @RequestMapping("/api")
33 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 38 @RequestMapping(value = "/relation", method = RequestMethod.POST)
37 39 @ResponseStatus(value = HttpStatus.OK)
38 40 public void saveRelation(@RequestBody EntityRelation relation) throws ThingsboardException {
... ... @@ -40,17 +42,22 @@ public class EntityRelationController extends BaseController {
40 42 checkNotNull(relation);
41 43 checkEntityId(relation.getFrom());
42 44 checkEntityId(relation.getTo());
  45 + if (relation.getTypeGroup() == null) {
  46 + relation.setTypeGroup(RelationTypeGroup.COMMON);
  47 + }
43 48 relationService.saveRelation(relation).get();
44 49 } catch (Exception e) {
45 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 55 @RequestMapping(value = "/relation", method = RequestMethod.DELETE, params = {"fromId", "fromType", "relationType", "toId", "toType"})
51 56 @ResponseStatus(value = HttpStatus.OK)
52 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 61 @RequestParam("toId") String strToId, @RequestParam("toType") String strToType) throws ThingsboardException {
55 62 checkParameter("fromId", strFromId);
56 63 checkParameter("fromType", strFromType);
... ... @@ -61,8 +68,9 @@ public class EntityRelationController extends BaseController {
61 68 EntityId toId = EntityIdFactory.getByTypeAndId(strToType, strToId);
62 69 checkEntityId(fromId);
63 70 checkEntityId(toId);
  71 + RelationTypeGroup relationTypeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
64 72 try {
65   - Boolean found = relationService.deleteRelation(fromId, toId, strRelationType).get();
  73 + Boolean found = relationService.deleteRelation(fromId, toId, strRelationType, relationTypeGroup).get();
66 74 if (!found) {
67 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 79 }
72 80 }
73 81
74   - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
  82 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN', 'CUSTOMER_USER')")
75 83 @RequestMapping(value = "/relations", method = RequestMethod.DELETE, params = {"id", "type"})
76 84 @ResponseStatus(value = HttpStatus.OK)
77 85 public void deleteRelations(@RequestParam("entityId") String strId,
... ... @@ -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 99 @RequestMapping(value = "/relation", method = RequestMethod.GET, params = {"fromId", "fromType", "relationType", "toId", "toType"})
92 100 @ResponseStatus(value = HttpStatus.OK)
93 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 105 @RequestParam("toId") String strToId, @RequestParam("toType") String strToType) throws ThingsboardException {
96 106 try {
97 107 checkParameter("fromId", strFromId);
... ... @@ -103,7 +113,8 @@ public class EntityRelationController extends BaseController {
103 113 EntityId toId = EntityIdFactory.getByTypeAndId(strToType, strToId);
104 114 checkEntityId(fromId);
105 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 118 if (!found) {
108 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 123 }
113 124 }
114 125
115   - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
  126 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
116 127 @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"fromId", "fromType"})
117 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 150 checkParameter("fromId", strFromId);
120 151 checkParameter("fromType", strFromType);
121 152 EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
122 153 checkEntityId(entityId);
  154 + RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
123 155 try {
124   - return checkNotNull(relationService.findByFrom(entityId).get());
  156 + return checkNotNull(relationService.findInfoByFrom(entityId, typeGroup).get());
125 157 } catch (Exception e) {
126 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 163 @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"fromId", "fromType", "relationType"})
132 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 169 checkParameter("fromId", strFromId);
136 170 checkParameter("fromType", strFromType);
137 171 checkParameter("relationType", strRelationType);
138 172 EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
139 173 checkEntityId(entityId);
  174 + RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
140 175 try {
141   - return checkNotNull(relationService.findByFromAndType(entityId, strRelationType).get());
  176 + return checkNotNull(relationService.findByFromAndType(entityId, strRelationType, typeGroup).get());
142 177 } catch (Exception e) {
143 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 183 @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"toId", "toType"})
149 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 188 checkParameter("toId", strToId);
152 189 checkParameter("toType", strToType);
153 190 EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId);
154 191 checkEntityId(entityId);
  192 + RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
155 193 try {
156   - return checkNotNull(relationService.findByTo(entityId).get());
  194 + return checkNotNull(relationService.findByTo(entityId, typeGroup).get());
157 195 } catch (Exception e) {
158 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 219 @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"toId", "toType", "relationType"})
164 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 225 checkParameter("toId", strToId);
168 226 checkParameter("toType", strToType);
169 227 checkParameter("relationType", strRelationType);
170 228 EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId);
171 229 checkEntityId(entityId);
  230 + RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
172 231 try {
173   - return checkNotNull(relationService.findByToAndType(entityId, strRelationType).get());
  232 + return checkNotNull(relationService.findByToAndType(entityId, strRelationType, typeGroup).get());
174 233 } catch (Exception e) {
175 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 239 @RequestMapping(value = "/relations", method = RequestMethod.POST)
181 240 @ResponseBody
182 241 public List<EntityRelation> findByQuery(@RequestBody EntityRelationsQuery query) throws ThingsboardException {
... ... @@ -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 19 address: "${HTTP_BIND_ADDRESS:0.0.0.0}"
20 20 # Server bind port
21 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 35 # Zookeeper connection parameters. Used for service discovery.
30 36 zk:
... ... @@ -79,12 +85,18 @@ mqtt:
79 85 leak_detector_level: "${NETTY_LEASK_DETECTOR_LVL:DISABLED}"
80 86 boss_group_thread_count: "${NETTY_BOSS_GROUP_THREADS:1}"
81 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 101 # CoAP server parameters
90 102 coap:
... ...
... ... @@ -98,13 +98,15 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppC
98 98 @IntegrationTest("server.port:0")
99 99 public abstract class AbstractControllerTest {
100 100
  101 + protected static final String TEST_TENANT_NAME = "TEST TENANT";
  102 +
101 103 protected static final String SYS_ADMIN_EMAIL = "sysadmin@thingsboard.org";
102 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 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 110 private static final String CUSTOMER_USER_PASSWORD = "customer";
109 111
110 112 protected MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
... ... @@ -147,7 +149,7 @@ public abstract class AbstractControllerTest {
147 149 loginSysAdmin();
148 150
149 151 Tenant tenant = new Tenant();
150   - tenant.setTitle("Tenant");
  152 + tenant.setTitle(TEST_TENANT_NAME);
151 153 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
152 154 Assert.assertNotNull(savedTenant);
153 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 24 import java.util.List;
25 25
26 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 28 import org.thingsboard.server.common.data.id.CustomerId;
32 29 import org.thingsboard.server.common.data.id.DeviceCredentialsId;
33 30 import org.thingsboard.server.common.data.id.DeviceId;
... ... @@ -83,6 +80,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
83 80 public void testSaveDevice() throws Exception {
84 81 Device device = new Device();
85 82 device.setName("My device");
  83 + device.setType("default");
86 84 Device savedDevice = doPost("/api/device", device, Device.class);
87 85
88 86 Assert.assertNotNull(savedDevice);
... ... @@ -114,16 +112,49 @@ public class DeviceControllerTest extends AbstractControllerTest {
114 112 public void testFindDeviceById() throws Exception {
115 113 Device device = new Device();
116 114 device.setName("My device");
  115 + device.setType("default");
117 116 Device savedDevice = doPost("/api/device", device, Device.class);
118 117 Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class);
119 118 Assert.assertNotNull(foundDevice);
120 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 153 @Test
124 154 public void testDeleteDevice() throws Exception {
125 155 Device device = new Device();
126 156 device.setName("My device");
  157 + device.setType("default");
127 158 Device savedDevice = doPost("/api/device", device, Device.class);
128 159
129 160 doDelete("/api/device/"+savedDevice.getId().getId().toString())
... ... @@ -132,10 +163,20 @@ public class DeviceControllerTest extends AbstractControllerTest {
132 163 doGet("/api/device/"+savedDevice.getId().getId().toString())
133 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 176 @Test
137 177 public void testSaveDeviceWithEmptyName() throws Exception {
138 178 Device device = new Device();
  179 + device.setType("default");
139 180 doPost("/api/device", device)
140 181 .andExpect(status().isBadRequest())
141 182 .andExpect(statusReason(containsString("Device name should be specified")));
... ... @@ -145,6 +186,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
145 186 public void testAssignUnassignDeviceToCustomer() throws Exception {
146 187 Device device = new Device();
147 188 device.setName("My device");
  189 + device.setType("default");
148 190 Device savedDevice = doPost("/api/device", device, Device.class);
149 191
150 192 Customer customer = new Customer();
... ... @@ -170,6 +212,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
170 212 public void testAssignDeviceToNonExistentCustomer() throws Exception {
171 213 Device device = new Device();
172 214 device.setName("My device");
  215 + device.setType("default");
173 216 Device savedDevice = doPost("/api/device", device, Device.class);
174 217
175 218 doPost("/api/customer/" + UUIDs.timeBased().toString()
... ... @@ -203,6 +246,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
203 246
204 247 Device device = new Device();
205 248 device.setName("My device");
  249 + device.setType("default");
206 250 Device savedDevice = doPost("/api/device", device, Device.class);
207 251
208 252 doPost("/api/customer/" + savedCustomer.getId().getId().toString()
... ... @@ -219,6 +263,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
219 263 public void testFindDeviceCredentialsByDeviceId() throws Exception {
220 264 Device device = new Device();
221 265 device.setName("My device");
  266 + device.setType("default");
222 267 Device savedDevice = doPost("/api/device", device, Device.class);
223 268 DeviceCredentials deviceCredentials =
224 269 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
... ... @@ -229,6 +274,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
229 274 public void testSaveDeviceCredentials() throws Exception {
230 275 Device device = new Device();
231 276 device.setName("My device");
  277 + device.setType("default");
232 278 Device savedDevice = doPost("/api/device", device, Device.class);
233 279 DeviceCredentials deviceCredentials =
234 280 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
... ... @@ -255,6 +301,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
255 301 public void testSaveDeviceCredentialsWithEmptyCredentialsType() throws Exception {
256 302 Device device = new Device();
257 303 device.setName("My device");
  304 + device.setType("default");
258 305 Device savedDevice = doPost("/api/device", device, Device.class);
259 306 DeviceCredentials deviceCredentials =
260 307 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
... ... @@ -268,6 +315,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
268 315 public void testSaveDeviceCredentialsWithEmptyCredentialsId() throws Exception {
269 316 Device device = new Device();
270 317 device.setName("My device");
  318 + device.setType("default");
271 319 Device savedDevice = doPost("/api/device", device, Device.class);
272 320 DeviceCredentials deviceCredentials =
273 321 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
... ... @@ -281,6 +329,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
281 329 public void testSaveNonExistentDeviceCredentials() throws Exception {
282 330 Device device = new Device();
283 331 device.setName("My device");
  332 + device.setType("default");
284 333 Device savedDevice = doPost("/api/device", device, Device.class);
285 334 DeviceCredentials deviceCredentials =
286 335 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
... ... @@ -298,6 +347,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
298 347 public void testSaveDeviceCredentialsWithNonExistentDevice() throws Exception {
299 348 Device device = new Device();
300 349 device.setName("My device");
  350 + device.setType("default");
301 351 Device savedDevice = doPost("/api/device", device, Device.class);
302 352 DeviceCredentials deviceCredentials =
303 353 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
... ... @@ -307,9 +357,10 @@ public class DeviceControllerTest extends AbstractControllerTest {
307 357 }
308 358
309 359 @Test
310   - public void testSaveDeviceCredentialsWithInvalidCredemtialsIdLength() throws Exception {
  360 + public void testSaveDeviceCredentialsWithInvalidCredentialsIdLength() throws Exception {
311 361 Device device = new Device();
312 362 device.setName("My device");
  363 + device.setType("default");
313 364 Device savedDevice = doPost("/api/device", device, Device.class);
314 365 DeviceCredentials deviceCredentials =
315 366 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
... ... @@ -325,6 +376,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
325 376 for (int i=0;i<178;i++) {
326 377 Device device = new Device();
327 378 device.setName("Device"+i);
  379 + device.setType("default");
328 380 devices.add(doPost("/api/device", device, Device.class));
329 381 }
330 382 List<Device> loadedDevices = new ArrayList<>();
... ... @@ -355,6 +407,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
355 407 String name = title1+suffix;
356 408 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
357 409 device.setName(name);
  410 + device.setType("default");
358 411 devicesTitle1.add(doPost("/api/device", device, Device.class));
359 412 }
360 413 String title2 = "Device title 2";
... ... @@ -365,6 +418,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
365 418 String name = title2+suffix;
366 419 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
367 420 device.setName(name);
  421 + device.setType("default");
368 422 devicesTitle2.add(doPost("/api/device", device, Device.class));
369 423 }
370 424
... ... @@ -423,6 +477,89 @@ public class DeviceControllerTest extends AbstractControllerTest {
423 477 Assert.assertFalse(pageData.hasNext());
424 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 564 @Test
428 565 public void testFindCustomerDevices() throws Exception {
... ... @@ -435,6 +572,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
435 572 for (int i=0;i<128;i++) {
436 573 Device device = new Device();
437 574 device.setName("Device"+i);
  575 + device.setType("default");
438 576 device = doPost("/api/device", device, Device.class);
439 577 devices.add(doPost("/api/customer/" + customerId.getId().toString()
440 578 + "/device/" + device.getId().getId().toString(), Device.class));
... ... @@ -473,6 +611,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
473 611 String name = title1+suffix;
474 612 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
475 613 device.setName(name);
  614 + device.setType("default");
476 615 device = doPost("/api/device", device, Device.class);
477 616 devicesTitle1.add(doPost("/api/customer/" + customerId.getId().toString()
478 617 + "/device/" + device.getId().getId().toString(), Device.class));
... ... @@ -485,6 +624,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
485 624 String name = title2+suffix;
486 625 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
487 626 device.setName(name);
  627 + device.setType("default");
488 628 device = doPost("/api/device", device, Device.class);
489 629 devicesTitle2.add(doPost("/api/customer/" + customerId.getId().toString()
490 630 + "/device/" + device.getId().getId().toString(), Device.class));
... ... @@ -546,4 +686,96 @@ public class DeviceControllerTest extends AbstractControllerTest {
546 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 130 Assert.assertEquals(tenants, loadedTenants);
131 131
132 132 for (Tenant tenant : loadedTenants) {
133   - if (!tenant.getTitle().equals("Tenant")) {
  133 + if (!tenant.getTitle().equals(TEST_TENANT_NAME)) {
134 134 doDelete("/api/tenant/"+tenant.getId().getId().toString())
135 135 .andExpect(status().isOk());
136 136 }
... ...
... ... @@ -182,7 +182,7 @@ public class UserControllerTest extends AbstractControllerTest {
182 182 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
183 183 Assert.assertNotNull(savedTenant);
184 184
185   - String email = "tenant@thingsboard.org";
  185 + String email = TENANT_ADMIN_EMAIL;
186 186 User user = new User();
187 187 user.setAuthority(Authority.TENANT_ADMIN);
188 188 user.setTenantId(savedTenant.getId());
... ...
... ... @@ -47,6 +47,7 @@ public class HttpDeviceApiTest extends AbstractControllerTest {
47 47 loginTenantAdmin();
48 48 device = new Device();
49 49 device.setName("My device");
  50 + device.setType("default");
50 51 device = doPost("/api/device", device, Device.class);
51 52
52 53 deviceCredentials =
... ...
... ... @@ -15,12 +15,14 @@
15 15 */
16 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 20 import org.thingsboard.server.common.data.id.CustomerId;
19 21 import org.thingsboard.server.common.data.id.TenantId;
20 22
21 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 27 private static final long serialVersionUID = -1599722990298929275L;
26 28
... ... @@ -59,6 +61,12 @@ public class Customer extends ContactBased<CustomerId>{
59 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 70 public JsonNode getAdditionalInfo() {
63 71 return additionalInfo;
64 72 }
... ...
... ... @@ -15,11 +15,12 @@
15 15 */
16 16 package org.thingsboard.server.common.data;
17 17
  18 +import com.fasterxml.jackson.annotation.JsonProperty;
18 19 import org.thingsboard.server.common.data.id.CustomerId;
19 20 import org.thingsboard.server.common.data.id.DashboardId;
20 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 25 private TenantId tenantId;
25 26 private CustomerId customerId;
... ... @@ -65,6 +66,12 @@ public class DashboardInfo extends SearchTextBased<DashboardId> {
65 66 }
66 67
67 68 @Override
  69 + @JsonProperty(access = JsonProperty.Access.READ_ONLY)
  70 + public String getName() {
  71 + return title;
  72 + }
  73 +
  74 + @Override
68 75 public String getSearchText() {
69 76 return title;
70 77 }
... ...
... ... @@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.id.TenantId;
21 21
22 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 26 private static final long serialVersionUID = 2807343040519543363L;
27 27
... ... @@ -64,6 +64,7 @@ public class Device extends SearchTextBased<DeviceId> {
64 64 this.customerId = customerId;
65 65 }
66 66
  67 + @Override
67 68 public String getName() {
68 69 return name;
69 70 }
... ...
... ... @@ -13,33 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 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   -}
\ No newline at end of file
  16 +package org.thingsboard.server.common.data;
  17 +
  18 +public interface HasName {
  19 +
  20 + String getName();
  21 +
  22 +}
... ...
... ... @@ -15,11 +15,12 @@
15 15 */
16 16 package org.thingsboard.server.common.data;
17 17
  18 +import com.fasterxml.jackson.annotation.JsonProperty;
18 19 import org.thingsboard.server.common.data.id.TenantId;
19 20
20 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 25 private static final long serialVersionUID = 8057243243859922101L;
25 26
... ... @@ -50,6 +51,12 @@ public class Tenant extends ContactBased<TenantId>{
50 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 60 public String getRegion() {
54 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 15 */
16 16 package org.thingsboard.server.common.data;
17 17
  18 +import com.fasterxml.jackson.annotation.JsonProperty;
18 19 import org.thingsboard.server.common.data.id.CustomerId;
19 20 import org.thingsboard.server.common.data.id.TenantId;
20 21 import org.thingsboard.server.common.data.id.UserId;
... ... @@ -22,7 +23,7 @@ import org.thingsboard.server.common.data.security.Authority;
22 23
23 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 28 private static final long serialVersionUID = 8250339805336035966L;
28 29
... ... @@ -77,6 +78,12 @@ public class User extends SearchTextBased<UserId> {
77 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 87 public Authority getAuthority() {
81 88 return authority;
82 89 }
... ...
... ... @@ -15,26 +15,47 @@
15 15 */
16 16 package org.thingsboard.server.common.data.alarm;
17 17
  18 +import com.fasterxml.jackson.annotation.JsonProperty;
18 19 import com.fasterxml.jackson.databind.JsonNode;
  20 +import lombok.AllArgsConstructor;
  21 +import lombok.Builder;
19 22 import lombok.Data;
20 23 import org.thingsboard.server.common.data.BaseData;
  24 +import org.thingsboard.server.common.data.HasName;
21 25 import org.thingsboard.server.common.data.id.EntityId;
  26 +import org.thingsboard.server.common.data.id.TenantId;
22 27
23 28 /**
24 29 * Created by ashvayka on 11.05.17.
25 30 */
26 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 37 private String type;
34 38 private EntityId originator;
35 39 private AlarmSeverity severity;
36 40 private AlarmStatus status;
  41 + private long startTs;
  42 + private long endTs;
  43 + private long ackTs;
  44 + private long clearTs;
37 45 private JsonNode details;
38 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 15 */
16 16 package org.thingsboard.server.common.data.alarm;
17 17
  18 +import lombok.AllArgsConstructor;
  19 +import lombok.Builder;
18 20 import lombok.Data;
19 21 import org.thingsboard.server.common.data.id.EntityId;
  22 +import org.thingsboard.server.common.data.id.TenantId;
20 23 import org.thingsboard.server.common.data.page.TimePageLink;
21 24
22 25 /**
23 26 * Created by ashvayka on 11.05.17.
24 27 */
25 28 @Data
  29 +@Builder
  30 +@AllArgsConstructor
26 31 public class AlarmQuery {
27 32
28 33 private EntityId affectedEntityId;
... ...
... ... @@ -22,4 +22,12 @@ public enum AlarmStatus {
22 22
23 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 16 package org.thingsboard.server.common.data.asset;
17 17
18 18 import com.fasterxml.jackson.databind.JsonNode;
  19 +import org.thingsboard.server.common.data.HasName;
19 20 import org.thingsboard.server.common.data.SearchTextBased;
20 21 import org.thingsboard.server.common.data.id.AssetId;
21 22 import org.thingsboard.server.common.data.id.CustomerId;
22 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 27 private static final long serialVersionUID = 2807343040519543363L;
27 28
... ... @@ -64,6 +65,7 @@ public class Asset extends SearchTextBased<AssetId> {
64 65 this.customerId = customerId;
65 66 }
66 67
  68 + @Override
67 69 public String getName() {
68 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 16 package org.thingsboard.server.common.data.id;
17 17
18 18 import org.thingsboard.server.common.data.EntityType;
  19 +import org.thingsboard.server.common.data.alarm.AlarmId;
19 20
20 21 import java.util.UUID;
21 22
... ... @@ -50,6 +51,8 @@ public class EntityIdFactory {
50 51 return new DeviceId(uuid);
51 52 case ASSET:
52 53 return new AssetId(uuid);
  54 + case ALARM:
  55 + return new AlarmId(uuid);
53 56 }
54 57 throw new IllegalArgumentException("EntityType " + type + " is not supported!");
55 58 }
... ...
... ... @@ -15,13 +15,14 @@
15 15 */
16 16 package org.thingsboard.server.common.data.plugin;
17 17
  18 +import org.thingsboard.server.common.data.HasName;
18 19 import org.thingsboard.server.common.data.SearchTextBased;
19 20 import org.thingsboard.server.common.data.id.PluginId;
20 21 import org.thingsboard.server.common.data.id.TenantId;
21 22
22 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 27 private static final long serialVersionUID = 1L;
27 28
... ... @@ -75,6 +76,7 @@ public class PluginMetaData extends SearchTextBased<PluginId> {
75 76 this.tenantId = tenantId;
76 77 }
77 78
  79 + @Override
78 80 public String getName() {
79 81 return name;
80 82 }
... ...
... ... @@ -30,6 +30,7 @@ public class EntityRelation {
30 30 private EntityId from;
31 31 private EntityId to;
32 32 private String type;
  33 + private RelationTypeGroup typeGroup;
33 34 private JsonNode additionalInfo;
34 35
35 36 public EntityRelation() {
... ... @@ -37,21 +38,27 @@ public class EntityRelation {
37 38 }
38 39
39 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 49 this.from = from;
45 50 this.to = to;
46 51 this.type = type;
  52 + this.typeGroup = typeGroup;
47 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 64 public EntityId getFrom() {
... ... @@ -78,6 +85,14 @@ public class EntityRelation {
78 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 96 public JsonNode getAdditionalInfo() {
82 97 return additionalInfo;
83 98 }
... ... @@ -90,14 +105,22 @@ public class EntityRelation {
90 105 public boolean equals(Object o) {
91 106 if (this == o) return true;
92 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 118 @Override
100 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 17
18 18 import lombok.Data;
19 19 import lombok.ToString;
  20 +import org.thingsboard.server.common.data.HasName;
20 21 import org.thingsboard.server.common.data.SearchTextBased;
21 22 import org.thingsboard.server.common.data.id.CustomerId;
22 23 import org.thingsboard.server.common.data.id.RuleId;
... ... @@ -26,7 +27,7 @@ import com.fasterxml.jackson.databind.JsonNode;
26 27 import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
27 28
28 29 @Data
29   -public class RuleMetaData extends SearchTextBased<RuleId> {
  30 +public class RuleMetaData extends SearchTextBased<RuleId> implements HasName {
30 31
31 32 private static final long serialVersionUID = -5656679015122935465L;
32 33
... ... @@ -66,4 +67,9 @@ public class RuleMetaData extends SearchTextBased<RuleId> {
66 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 127 log.debug("Save entity {}", entity);
128 128 if (entity.getId() == null) {
129 129 entity.setId(UUIDs.timeBased());
130   - } else {
  130 + } else if (isDeleteOnSave()) {
131 131 removeById(entity.getId());
132 132 }
133 133 Statement saveStatement = getSaveQuery(entity);
... ... @@ -136,6 +136,10 @@ public abstract class AbstractModelDao<T extends BaseEntity<?>> extends Abstract
136 136 return new EntityResultSet<>(resultSet, entity);
137 137 }
138 138
  139 + protected boolean isDeleteOnSave() {
  140 + return true;
  141 + }
  142 +
139 143 public T save(T entity) {
140 144 return saveWithResult(entity).getEntity();
141 145 }
... ... @@ -161,9 +165,18 @@ public abstract class AbstractModelDao<T extends BaseEntity<?>> extends Abstract
161 165 return getSession().execute(delete);
162 166 }
163 167
164   -
165 168 public List<T> find() {
166 169 log.debug("Get all entities from column family {}", getColumnFamilyName());
167 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 47 return findPageWithTimeSearch(searchView, clauses, Collections.singletonList(ordering), pageLink);
48 48 }
49 49
50   -
51 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 71 Select select = select().from(searchView);
53 72 Where query = select.where();
54 73 for (Clause clause : clauses) {
... ... @@ -57,34 +76,35 @@ public abstract class AbstractSearchTimeDao<T extends BaseEntity<?>> extends Abs
57 76 query.limit(pageLink.getLimit());
58 77 if (pageLink.isAscOrder()) {
59 78 if (pageLink.getIdOffset() != null) {
60   - query.and(QueryBuilder.gt(ModelConstants.ID_PROPERTY, pageLink.getIdOffset()));
  79 + query.and(QueryBuilder.gt(idColumn, pageLink.getIdOffset()));
61 80 } else if (pageLink.getStartTime() != null) {
62 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 84 if (pageLink.getEndTime() != null) {
66 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 88 } else {
70 89 if (pageLink.getIdOffset() != null) {
71   - query.and(QueryBuilder.lt(ModelConstants.ID_PROPERTY, pageLink.getIdOffset()));
  90 + query.and(QueryBuilder.lt(idColumn, pageLink.getIdOffset()));
72 91 } else if (pageLink.getEndTime() != null) {
73 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 95 if (pageLink.getStartTime() != null) {
77 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 100 List<Ordering> orderings = new ArrayList<>(topLevelOrderings);
82 101 if (pageLink.isAscOrder()) {
83   - orderings.add(QueryBuilder.asc(ModelConstants.ID_PROPERTY));
  102 + orderings.add(QueryBuilder.asc(idColumn));
84 103 } else {
85   - orderings.add(QueryBuilder.desc(ModelConstants.ID_PROPERTY));
  104 + orderings.add(QueryBuilder.desc(idColumn));
86 105 }
87 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 15 */
16 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 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 21 import org.thingsboard.server.common.data.alarm.AlarmQuery;
22 22 import org.thingsboard.server.common.data.page.TimePageData;
23 23
24   -import java.util.Optional;
25   -
26 24 /**
27 25 * Created by ashvayka on 11.05.17.
28 26 */
29 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 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 16 package org.thingsboard.server.dao.asset;
17 17
18 18 import com.google.common.util.concurrent.ListenableFuture;
19   -import org.thingsboard.server.common.data.Device;
20 19 import org.thingsboard.server.common.data.asset.Asset;
21 20 import org.thingsboard.server.common.data.page.TextPageLink;
22 21 import org.thingsboard.server.dao.Dao;
23 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 25 import java.util.List;
27 26 import java.util.Optional;
... ... @@ -51,6 +50,16 @@ public interface AssetDao extends Dao<AssetEntity> {
51 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 63 * Find assets by tenantId and assets Ids.
55 64 *
56 65 * @param tenantId the tenantId
... ... @@ -70,6 +79,17 @@ public interface AssetDao extends Dao<AssetEntity> {
70 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 93 * Find assets by tenantId, customerId and assets Ids.
74 94 *
75 95 * @param tenantId the tenantId
... ... @@ -87,4 +107,12 @@ public interface AssetDao extends Dao<AssetEntity> {
87 107 * @return the optional asset object
88 108 */
89 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 15 */
16 16 package org.thingsboard.server.dao.asset;
17 17
  18 +import com.datastax.driver.core.ResultSet;
  19 +import com.datastax.driver.core.ResultSetFuture;
18 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 24 import com.google.common.util.concurrent.ListenableFuture;
20 25 import lombok.extern.slf4j.Slf4j;
21 26 import org.springframework.stereotype.Component;
... ... @@ -23,7 +28,9 @@ import org.thingsboard.server.common.data.asset.Asset;
23 28 import org.thingsboard.server.common.data.page.TextPageLink;
24 29 import org.thingsboard.server.dao.AbstractSearchTextDao;
25 30 import org.thingsboard.server.dao.model.AssetEntity;
  31 +import org.thingsboard.server.dao.model.TenantAssetTypeEntity;
26 32
  33 +import javax.annotation.Nullable;
27 34 import java.util.*;
28 35
29 36 import static com.datastax.driver.core.querybuilder.QueryBuilder.*;
... ... @@ -60,6 +67,16 @@ public class AssetDaoImpl extends AbstractSearchTextDao<AssetEntity> implements
60 67 }
61 68
62 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 80 public ListenableFuture<List<AssetEntity>> findAssetsByTenantIdAndIdsAsync(UUID tenantId, List<UUID> assetIds) {
64 81 log.debug("Try to find assets by tenantId [{}] and asset Ids [{}]", tenantId, assetIds);
65 82 Select select = select().from(getColumnFamilyName());
... ... @@ -82,6 +99,19 @@ public class AssetDaoImpl extends AbstractSearchTextDao<AssetEntity> implements
82 99 }
83 100
84 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 115 public ListenableFuture<List<AssetEntity>> findAssetsByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> assetIds) {
86 116 log.debug("Try to find assets by tenantId [{}], customerId [{}] and asset Ids [{}]", tenantId, customerId, assetIds);
87 117 Select select = select().from(getColumnFamilyName());
... ... @@ -101,4 +131,24 @@ public class AssetDaoImpl extends AbstractSearchTextDao<AssetEntity> implements
101 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 17
18 18 import com.google.common.util.concurrent.ListenableFuture;
19 19 import org.thingsboard.server.common.data.asset.Asset;
  20 +import org.thingsboard.server.common.data.asset.TenantAssetType;
20 21 import org.thingsboard.server.common.data.id.AssetId;
21 22 import org.thingsboard.server.common.data.id.CustomerId;
22 23 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -34,7 +35,7 @@ public interface AssetService {
34 35
35 36 Optional<Asset> findAssetByTenantIdAndName(TenantId tenantId, String name);
36 37
37   - Asset saveAsset(Asset device);
  38 + Asset saveAsset(Asset asset);
38 39
39 40 Asset assignAssetToCustomer(AssetId assetId, CustomerId customerId);
40 41
... ... @@ -44,16 +45,21 @@ public interface AssetService {
44 45
45 46 TextPageData<Asset> findAssetsByTenantId(TenantId tenantId, TextPageLink pageLink);
46 47
  48 + TextPageData<Asset> findAssetsByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink);
  49 +
47 50 ListenableFuture<List<Asset>> findAssetsByTenantIdAndIdsAsync(TenantId tenantId, List<AssetId> assetIds);
48 51
49 52 void deleteAssetsByTenantId(TenantId tenantId);
50 53
51 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 58 ListenableFuture<List<Asset>> findAssetsByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<AssetId> assetIds);
54 59
55 60 void unassignCustomerAssets(TenantId tenantId, CustomerId customerId);
56 61
57 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 26 import org.springframework.util.StringUtils;
27 27 import org.thingsboard.server.common.data.EntityType;
28 28 import org.thingsboard.server.common.data.asset.Asset;
  29 +import org.thingsboard.server.common.data.asset.TenantAssetType;
29 30 import org.thingsboard.server.common.data.id.AssetId;
30 31 import org.thingsboard.server.common.data.id.CustomerId;
31 32 import org.thingsboard.server.common.data.id.EntityId;
... ... @@ -34,12 +35,9 @@ import org.thingsboard.server.common.data.page.TextPageData;
34 35 import org.thingsboard.server.common.data.page.TextPageLink;
35 36 import org.thingsboard.server.common.data.relation.EntityRelation;
36 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 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 41 import org.thingsboard.server.dao.relation.EntitySearchDirection;
44 42 import org.thingsboard.server.dao.service.DataValidator;
45 43 import org.thingsboard.server.dao.service.PaginatedRemover;
... ... @@ -57,7 +55,7 @@ import static org.thingsboard.server.dao.service.Validator.*;
57 55
58 56 @Service
59 57 @Slf4j
60   -public class BaseAssetService extends BaseEntityService implements AssetService {
  58 +public class BaseAssetService extends AbstractEntityService implements AssetService {
61 59
62 60 @Autowired
63 61 private AssetDao assetDao;
... ... @@ -132,7 +130,18 @@ public class BaseAssetService extends BaseEntityService implements AssetService
132 130 validatePageLink(pageLink, "Incorrect page link " + pageLink);
133 131 List<AssetEntity> assetEntities = assetDao.findAssetsByTenantId(tenantId.getId(), pageLink);
134 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 147 @Override
... ... @@ -159,7 +168,19 @@ public class BaseAssetService extends BaseEntityService implements AssetService
159 168 validatePageLink(pageLink, "Incorrect page link " + pageLink);
160 169 List<AssetEntity> assetEntities = assetDao.findAssetsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink);
161 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 186 @Override
... ... @@ -207,6 +228,25 @@ public class BaseAssetService extends BaseEntityService implements AssetService
207 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 250 private DataValidator<Asset> assetValidator =
211 251 new DataValidator<Asset>() {
212 252
... ... @@ -232,6 +272,9 @@ public class BaseAssetService extends BaseEntityService implements AssetService
232 272
233 273 @Override
234 274 protected void validateDataImpl(Asset asset) {
  275 + if (StringUtils.isEmpty(asset.getType())) {
  276 + throw new DataValidationException("Asset type should be specified!");
  277 + }
235 278 if (StringUtils.isEmpty(asset.getName())) {
236 279 throw new DataValidationException("Asset name should be specified!");
237 280 }
... ...
... ... @@ -45,7 +45,6 @@ public class ServiceCacheConfiguration {
45 45 @Value("${cache.device_credentials.time_to_live}")
46 46 private Integer cacheDeviceCredentialsTTL;
47 47
48   -
49 48 @Value("${zk.enabled}")
50 49 private boolean zkEnabled;
51 50 @Value("${zk.url}")
... ...
... ... @@ -31,17 +31,15 @@ import com.google.common.util.concurrent.ListenableFuture;
31 31 import lombok.extern.slf4j.Slf4j;
32 32 import org.apache.commons.lang3.StringUtils;
33 33 import org.thingsboard.server.common.data.Customer;
34   -import org.thingsboard.server.common.data.asset.Asset;
35 34 import org.thingsboard.server.common.data.id.CustomerId;
36 35 import org.thingsboard.server.common.data.id.TenantId;
37 36 import org.thingsboard.server.common.data.page.TextPageData;
38 37 import org.thingsboard.server.common.data.page.TextPageLink;
39 38 import org.thingsboard.server.dao.dashboard.DashboardService;
40 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 41 import org.thingsboard.server.dao.exception.DataValidationException;
43 42 import org.thingsboard.server.dao.exception.IncorrectParameterException;
44   -import org.thingsboard.server.dao.model.AssetEntity;
45 43 import org.thingsboard.server.dao.model.CustomerEntity;
46 44 import org.thingsboard.server.dao.model.TenantEntity;
47 45 import org.thingsboard.server.dao.service.DataValidator;
... ... @@ -53,7 +51,7 @@ import org.springframework.stereotype.Service;
53 51 import org.thingsboard.server.dao.service.Validator;
54 52 @Service
55 53 @Slf4j
56   -public class CustomerServiceImpl extends BaseEntityService implements CustomerService {
  54 +public class CustomerServiceImpl extends AbstractEntityService implements CustomerService {
57 55
58 56 private static final String PUBLIC_CUSTOMER_TITLE = "Public";
59 57
... ...
... ... @@ -15,6 +15,7 @@
15 15 */
16 16 package org.thingsboard.server.dao.dashboard;
17 17
  18 +import com.google.common.util.concurrent.ListenableFuture;
18 19 import org.thingsboard.server.common.data.Dashboard;
19 20 import org.thingsboard.server.common.data.DashboardInfo;
20 21 import org.thingsboard.server.common.data.id.CustomerId;
... ... @@ -27,8 +28,12 @@ public interface DashboardService {
27 28
28 29 public Dashboard findDashboardById(DashboardId dashboardId);
29 30
  31 + public ListenableFuture<Dashboard> findDashboardByIdAsync(DashboardId dashboardId);
  32 +
30 33 public DashboardInfo findDashboardInfoById(DashboardId dashboardId);
31 34
  35 + public ListenableFuture<DashboardInfo> findDashboardInfoByIdAsync(DashboardId dashboardId);
  36 +
32 37 public Dashboard saveDashboard(Dashboard dashboard);
33 38
34 39 public Dashboard assignDashboardToCustomer(DashboardId dashboardId, CustomerId customerId);
... ...
... ... @@ -17,9 +17,13 @@ package org.thingsboard.server.dao.dashboard;
17 17
18 18 import static org.thingsboard.server.dao.DaoUtil.convertDataList;
19 19 import static org.thingsboard.server.dao.DaoUtil.getData;
  20 +import static org.thingsboard.server.dao.service.Validator.validateId;
20 21
21 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 27 import lombok.extern.slf4j.Slf4j;
24 28 import org.apache.commons.lang3.StringUtils;
25 29 import org.thingsboard.server.common.data.Dashboard;
... ... @@ -30,7 +34,7 @@ import org.thingsboard.server.common.data.id.TenantId;
30 34 import org.thingsboard.server.common.data.page.TextPageData;
31 35 import org.thingsboard.server.common.data.page.TextPageLink;
32 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 38 import org.thingsboard.server.dao.exception.DataValidationException;
35 39 import org.thingsboard.server.dao.model.*;
36 40 import org.thingsboard.server.dao.service.DataValidator;
... ... @@ -42,7 +46,7 @@ import org.thingsboard.server.dao.service.Validator;
42 46
43 47 @Service
44 48 @Slf4j
45   -public class DashboardServiceImpl extends BaseEntityService implements DashboardService {
  49 +public class DashboardServiceImpl extends AbstractEntityService implements DashboardService {
46 50
47 51 @Autowired
48 52 private DashboardDao dashboardDao;
... ... @@ -65,6 +69,14 @@ public class DashboardServiceImpl extends BaseEntityService implements Dashboard
65 69 }
66 70
67 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 80 public DashboardInfo findDashboardInfoById(DashboardId dashboardId) {
69 81 log.trace("Executing findDashboardInfoById [{}]", dashboardId);
70 82 Validator.validateId(dashboardId, "Incorrect dashboardId " + dashboardId);
... ... @@ -73,6 +85,14 @@ public class DashboardServiceImpl extends BaseEntityService implements Dashboard
73 85 }
74 86
75 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 96 public Dashboard saveDashboard(Dashboard dashboard) {
77 97 log.trace("Executing saveDashboard [{}]", dashboard);
78 98 dashboardValidator.validate(dashboard);
... ...
... ... @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.Device;
24 24 import org.thingsboard.server.common.data.page.TextPageLink;
25 25 import org.thingsboard.server.dao.Dao;
26 26 import org.thingsboard.server.dao.model.DeviceEntity;
  27 +import org.thingsboard.server.dao.model.TenantDeviceTypeEntity;
27 28
28 29 /**
29 30 * The Interface DeviceDao.
... ... @@ -49,6 +50,16 @@ public interface DeviceDao extends Dao<DeviceEntity> {
49 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 63 * Find devices by tenantId and devices Ids.
53 64 *
54 65 * @param tenantId the tenantId
... ... @@ -68,6 +79,18 @@ public interface DeviceDao extends Dao<DeviceEntity> {
68 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 94 * Find devices by tenantId, customerId and devices Ids.
72 95 *
73 96 * @param tenantId the tenantId
... ... @@ -85,4 +108,11 @@ public interface DeviceDao extends Dao<DeviceEntity> {
85 108 * @return the optional device object
86 109 */
87 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 22
23 23 import java.util.*;
24 24
  25 +import com.datastax.driver.core.ResultSet;
  26 +import com.datastax.driver.core.ResultSetFuture;
25 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 31 import com.google.common.util.concurrent.ListenableFuture;
27 32 import lombok.extern.slf4j.Slf4j;
28 33 import org.springframework.stereotype.Component;
... ... @@ -32,6 +37,9 @@ import org.thingsboard.server.dao.AbstractSearchTextDao;
32 37 import org.thingsboard.server.dao.model.DeviceEntity;
33 38 import org.slf4j.Logger;
34 39 import org.slf4j.LoggerFactory;
  40 +import org.thingsboard.server.dao.model.TenantDeviceTypeEntity;
  41 +
  42 +import javax.annotation.Nullable;
35 43
36 44 @Component
37 45 @Slf4j
... ... @@ -64,6 +72,16 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement
64 72 }
65 73
66 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 85 public ListenableFuture<List<DeviceEntity>> findDevicesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> deviceIds) {
68 86 log.debug("Try to find devices by tenantId [{}] and device Ids [{}]", tenantId, deviceIds);
69 87 Select select = select().from(getColumnFamilyName());
... ... @@ -75,7 +93,7 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement
75 93
76 94 @Override
77 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 97 List<DeviceEntity> deviceEntities = findPageWithTextSearch(DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
80 98 Arrays.asList(eq(DEVICE_CUSTOMER_ID_PROPERTY, customerId),
81 99 eq(DEVICE_TENANT_ID_PROPERTY, tenantId)),
... ... @@ -86,6 +104,19 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement
86 104 }
87 105
88 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 120 public ListenableFuture<List<DeviceEntity>> findDevicesByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> deviceIds) {
90 121 log.debug("Try to find devices by tenantId [{}], customerId [{}] and device Ids [{}]", tenantId, customerId, deviceIds);
91 122 Select select = select().from(getColumnFamilyName());
... ... @@ -105,4 +136,24 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement
105 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 17
18 18 import com.google.common.util.concurrent.ListenableFuture;
19 19 import org.thingsboard.server.common.data.Device;
  20 +import org.thingsboard.server.common.data.TenantDeviceType;
20 21 import org.thingsboard.server.common.data.id.CustomerId;
21 22 import org.thingsboard.server.common.data.id.DeviceId;
22 23 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -44,16 +45,22 @@ public interface DeviceService {
44 45
45 46 TextPageData<Device> findDevicesByTenantId(TenantId tenantId, TextPageLink pageLink);
46 47
  48 + TextPageData<Device> findDevicesByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink);
  49 +
47 50 ListenableFuture<List<Device>> findDevicesByTenantIdAndIdsAsync(TenantId tenantId, List<DeviceId> deviceIds);
48 51
49 52 void deleteDevicesByTenantId(TenantId tenantId);
50 53
51 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 58 ListenableFuture<List<Device>> findDevicesByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<DeviceId> deviceIds);
54 59
55 60 void unassignCustomerDevices(TenantId tenantId, CustomerId customerId);
56 61
57 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 26 import org.springframework.util.StringUtils;
27 27 import org.thingsboard.server.common.data.Device;
28 28 import org.thingsboard.server.common.data.EntityType;
  29 +import org.thingsboard.server.common.data.TenantDeviceType;
29 30 import org.thingsboard.server.common.data.id.CustomerId;
30 31 import org.thingsboard.server.common.data.id.DeviceId;
31 32 import org.thingsboard.server.common.data.id.EntityId;
... ... @@ -36,10 +37,11 @@ import org.thingsboard.server.common.data.relation.EntityRelation;
36 37 import org.thingsboard.server.common.data.security.DeviceCredentials;
37 38 import org.thingsboard.server.common.data.security.DeviceCredentialsType;
38 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 41 import org.thingsboard.server.dao.exception.DataValidationException;
41 42 import org.thingsboard.server.dao.model.CustomerEntity;
42 43 import org.thingsboard.server.dao.model.DeviceEntity;
  44 +import org.thingsboard.server.dao.model.TenantDeviceTypeEntity;
43 45 import org.thingsboard.server.dao.model.TenantEntity;
44 46 import org.thingsboard.server.dao.relation.EntitySearchDirection;
45 47 import org.thingsboard.server.dao.service.DataValidator;
... ... @@ -47,9 +49,7 @@ import org.thingsboard.server.dao.service.PaginatedRemover;
47 49 import org.thingsboard.server.dao.tenant.TenantDao;
48 50
49 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 53 import java.util.stream.Collectors;
54 54
55 55 import static org.thingsboard.server.dao.DaoUtil.*;
... ... @@ -58,7 +58,7 @@ import static org.thingsboard.server.dao.service.Validator.*;
58 58
59 59 @Service
60 60 @Slf4j
61   -public class DeviceServiceImpl extends BaseEntityService implements DeviceService {
  61 +public class DeviceServiceImpl extends AbstractEntityService implements DeviceService {
62 62
63 63 @Autowired
64 64 private DeviceDao deviceDao;
... ... @@ -148,7 +148,18 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic
148 148 validatePageLink(pageLink, "Incorrect page link " + pageLink);
149 149 List<DeviceEntity> deviceEntities = deviceDao.findDevicesByTenantId(tenantId.getId(), pageLink);
150 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 165 @Override
... ... @@ -176,7 +187,19 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic
176 187 validatePageLink(pageLink, "Incorrect page link " + pageLink);
177 188 List<DeviceEntity> deviceEntities = deviceDao.findDevicesByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink);
178 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 205 @Override
... ... @@ -224,6 +247,25 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic
224 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 269 private DataValidator<Device> deviceValidator =
228 270 new DataValidator<Device>() {
229 271
... ... @@ -249,6 +291,9 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic
249 291
250 292 @Override
251 293 protected void validateDataImpl(Device device) {
  294 + if (StringUtils.isEmpty(device.getType())) {
  295 + throw new DataValidationException("Device type should be specified!");
  296 + }
252 297 if (StringUtils.isEmpty(device.getName())) {
253 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 15 */
16 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 21 import lombok.extern.slf4j.Slf4j;
19 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 38 * Created by ashvayka on 04.05.17.
25 39 */
  40 +@Service
26 41 @Slf4j
27   -public class BaseEntityService {
  42 +public class BaseEntityService extends AbstractEntityService implements EntityService {
28 43
29 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 +}
\ No newline at end of file
... ...
... ... @@ -49,12 +49,13 @@ public final class AssetEntity implements SearchTextEntity<Asset> {
49 49 @Column(name = ASSET_CUSTOMER_ID_PROPERTY)
50 50 private UUID customerId;
51 51
52   - @Column(name = ASSET_NAME_PROPERTY)
53   - private String name;
54   -
  52 + @PartitionKey(value = 3)
55 53 @Column(name = ASSET_TYPE_PROPERTY)
56 54 private String type;
57 55
  56 + @Column(name = ASSET_NAME_PROPERTY)
  57 + private String name;
  58 +
58 59 @Column(name = SEARCH_TEXT_PROPERTY)
59 60 private String searchText;
60 61
... ...
... ... @@ -49,12 +49,13 @@ public final class DeviceEntity implements SearchTextEntity<Device> {
49 49 @Column(name = DEVICE_CUSTOMER_ID_PROPERTY)
50 50 private UUID customerId;
51 51
52   - @Column(name = DEVICE_NAME_PROPERTY)
53   - private String name;
54   -
  52 + @PartitionKey(value = 3)
55 53 @Column(name = DEVICE_TYPE_PROPERTY)
56 54 private String type;
57 55
  56 + @Column(name = DEVICE_NAME_PROPERTY)
  57 + private String name;
  58 +
58 59 @Column(name = SEARCH_TEXT_PROPERTY)
59 60 private String searchText;
60 61
... ...
... ... @@ -124,8 +124,11 @@ public class ModelConstants {
124 124 public static final String DEVICE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
125 125
126 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 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 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 134 * Cassandra asset constants.
... ... @@ -138,8 +141,30 @@ public class ModelConstants {
138 141 public static final String ASSET_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
139 142
140 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 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 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 170 * Cassandra entity relation constants.
... ... @@ -150,7 +175,9 @@ public class ModelConstants {
150 175 public static final String RELATION_TO_ID_PROPERTY = "to_id";
151 176 public static final String RELATION_TO_TYPE_PROPERTY = "to_type";
152 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 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 22 import org.springframework.beans.factory.annotation.Autowired;
23 23 import org.springframework.stereotype.Service;
24 24 import org.thingsboard.server.common.data.id.PluginId;
25   -import org.thingsboard.server.common.data.id.RuleId;
26 25 import org.thingsboard.server.common.data.id.TenantId;
27 26 import org.thingsboard.server.common.data.page.TextPageData;
28 27 import org.thingsboard.server.common.data.page.TextPageLink;
... ... @@ -30,9 +29,8 @@ import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
30 29 import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
31 30 import org.thingsboard.server.common.data.plugin.ComponentType;
32 31 import org.thingsboard.server.common.data.plugin.PluginMetaData;
33   -import org.thingsboard.server.common.data.rule.RuleMetaData;
34 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 34 import org.thingsboard.server.dao.exception.DataValidationException;
37 35 import org.thingsboard.server.dao.exception.DatabaseException;
38 36 import org.thingsboard.server.dao.exception.IncorrectParameterException;
... ... @@ -55,7 +53,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId;
55 53
56 54 @Service
57 55 @Slf4j
58   -public class BasePluginService extends BaseEntityService implements PluginService {
  56 +public class BasePluginService extends AbstractEntityService implements PluginService {
59 57
60 58 //TODO: move to a better place.
61 59 public static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID);
... ...
... ... @@ -16,23 +16,34 @@
16 16 package org.thingsboard.server.dao.relation;
17 17
18 18 import com.datastax.driver.core.*;
  19 +import com.datastax.driver.core.querybuilder.QueryBuilder;
  20 +import com.datastax.driver.core.querybuilder.Select;
19 21 import com.fasterxml.jackson.databind.JsonNode;
20 22 import com.google.common.base.Function;
21 23 import com.google.common.util.concurrent.Futures;
22 24 import com.google.common.util.concurrent.ListenableFuture;
23 25 import lombok.extern.slf4j.Slf4j;
24 26 import org.springframework.stereotype.Component;
  27 +import org.thingsboard.server.common.data.EntityType;
25 28 import org.thingsboard.server.common.data.id.EntityId;
26 29 import org.thingsboard.server.common.data.id.EntityIdFactory;
  30 +import org.thingsboard.server.common.data.page.TimePageLink;
27 31 import org.thingsboard.server.common.data.relation.EntityRelation;
  32 +import org.thingsboard.server.common.data.relation.RelationTypeGroup;
28 33 import org.thingsboard.server.dao.AbstractAsyncDao;
  34 +import org.thingsboard.server.dao.AbstractSearchTimeDao;
29 35 import org.thingsboard.server.dao.model.ModelConstants;
  36 +import org.thingsboard.server.dao.model.type.RelationTypeGroupCodec;
30 37
31 38 import javax.annotation.Nullable;
32 39 import javax.annotation.PostConstruct;
33 40 import java.util.ArrayList;
  41 +import java.util.Arrays;
34 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 48 * Created by ashvayka on 25.04.17.
38 49 */
... ... @@ -45,12 +56,15 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
45 56 ModelConstants.RELATION_FROM_TYPE_PROPERTY + "," +
46 57 ModelConstants.RELATION_TO_ID_PROPERTY + "," +
47 58 ModelConstants.RELATION_TO_TYPE_PROPERTY + "," +
  59 + ModelConstants.RELATION_TYPE_GROUP_PROPERTY + "," +
48 60 ModelConstants.RELATION_TYPE_PROPERTY + "," +
49 61 ModelConstants.ADDITIONAL_INFO_PROPERTY;
50 62 public static final String FROM = " FROM ";
51 63 public static final String WHERE = " WHERE ";
52 64 public static final String AND = " AND ";
53 65
  66 + private static final RelationTypeGroupCodec relationTypeGroupCodec = new RelationTypeGroupCodec();
  67 +
54 68 private PreparedStatement saveStmt;
55 69 private PreparedStatement findAllByFromStmt;
56 70 private PreparedStatement findAllByFromAndTypeStmt;
... ... @@ -66,43 +80,52 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
66 80 }
67 81
68 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 88 return executeAsyncRead(from, stmt);
72 89 }
73 90
74 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 93 BoundStatement stmt = getFindAllByFromAndTypeStmt().bind()
77 94 .setUUID(0, from.getId())
78 95 .setString(1, from.getEntityType().name())
79   - .setString(2, relationType);
  96 + .set(2, typeGroup, relationTypeGroupCodec)
  97 + .setString(3, relationType);
80 98 return executeAsyncRead(from, stmt);
81 99 }
82 100
83 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 107 return executeAsyncRead(to, stmt);
87 108 }
88 109
89 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 112 BoundStatement stmt = getFindAllByToAndTypeStmt().bind()
92 113 .setUUID(0, to.getId())
93 114 .setString(1, to.getEntityType().name())
94   - .setString(2, relationType);
  115 + .set(2, typeGroup, relationTypeGroupCodec)
  116 + .setString(3, relationType);
95 117 return executeAsyncRead(to, stmt);
96 118 }
97 119
98 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 122 BoundStatement stmt = getCheckRelationStmt().bind()
101 123 .setUUID(0, from.getId())
102 124 .setString(1, from.getEntityType().name())
103 125 .setUUID(2, to.getId())
104 126 .setString(3, to.getEntityType().name())
105   - .setString(4, relationType);
  127 + .set(4, typeGroup, relationTypeGroupCodec)
  128 + .setString(5, relationType);
106 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 136 .setString(1, relation.getFrom().getEntityType().name())
114 137 .setUUID(2, relation.getTo().getId())
115 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 142 ResultSetFuture future = executeAsyncWrite(stmt);
119 143 return getBooleanListenableFuture(future);
120 144 }
121 145
122 146 @Override
123 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 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 153 BoundStatement stmt = getDeleteStmt().bind()
130 154 .setUUID(0, from.getId())
131 155 .setString(1, from.getEntityType().name())
132 156 .setUUID(2, to.getId())
133 157 .setString(3, to.getEntityType().name())
134   - .setString(4, relationType);
  158 + .set(4, typeGroup, relationTypeGroupCodec)
  159 + .setString(5, relationType);
135 160 ResultSetFuture future = executeAsyncWrite(stmt);
136 161 return getBooleanListenableFuture(future);
137 162 }
... ... @@ -145,6 +170,21 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
145 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 188 private PreparedStatement getSaveStmt() {
149 189 if (saveStmt == null) {
150 190 saveStmt = getSession().prepare("INSERT INTO " + ModelConstants.RELATION_COLUMN_FAMILY_NAME + " " +
... ... @@ -152,9 +192,10 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
152 192 "," + ModelConstants.RELATION_FROM_TYPE_PROPERTY +
153 193 "," + ModelConstants.RELATION_TO_ID_PROPERTY +
154 194 "," + ModelConstants.RELATION_TO_TYPE_PROPERTY +
  195 + "," + ModelConstants.RELATION_TYPE_GROUP_PROPERTY +
155 196 "," + ModelConstants.RELATION_TYPE_PROPERTY +
156 197 "," + ModelConstants.ADDITIONAL_INFO_PROPERTY + ")" +
157   - " VALUES(?, ?, ?, ?, ?, ?)");
  198 + " VALUES(?, ?, ?, ?, ?, ?, ?)");
158 199 }
159 200 return saveStmt;
160 201 }
... ... @@ -166,6 +207,7 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
166 207 AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ?" +
167 208 AND + ModelConstants.RELATION_TO_ID_PROPERTY + " = ?" +
168 209 AND + ModelConstants.RELATION_TO_TYPE_PROPERTY + " = ?" +
  210 + AND + ModelConstants.RELATION_TYPE_GROUP_PROPERTY + " = ?" +
169 211 AND + ModelConstants.RELATION_TYPE_PROPERTY + " = ?");
170 212 }
171 213 return deleteStmt;
... ... @@ -185,7 +227,8 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
185 227 findAllByFromStmt = getSession().prepare(SELECT_COLUMNS + " " +
186 228 FROM + ModelConstants.RELATION_COLUMN_FAMILY_NAME + " " +
187 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 233 return findAllByFromStmt;
191 234 }
... ... @@ -196,17 +239,20 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
196 239 FROM + ModelConstants.RELATION_COLUMN_FAMILY_NAME + " " +
197 240 WHERE + ModelConstants.RELATION_FROM_ID_PROPERTY + " = ? " +
198 241 AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ? " +
  242 + AND + ModelConstants.RELATION_TYPE_GROUP_PROPERTY + " = ? " +
199 243 AND + ModelConstants.RELATION_TYPE_PROPERTY + " = ? ");
200 244 }
201 245 return findAllByFromAndTypeStmt;
202 246 }
203 247
  248 +
204 249 private PreparedStatement getFindAllByToStmt() {
205 250 if (findAllByToStmt == null) {
206 251 findAllByToStmt = getSession().prepare(SELECT_COLUMNS + " " +
207 252 FROM + ModelConstants.RELATION_REVERSE_VIEW_NAME + " " +
208 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 257 return findAllByToStmt;
212 258 }
... ... @@ -217,11 +263,13 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
217 263 FROM + ModelConstants.RELATION_REVERSE_VIEW_NAME + " " +
218 264 WHERE + ModelConstants.RELATION_TO_ID_PROPERTY + " = ? " +
219 265 AND + ModelConstants.RELATION_TO_TYPE_PROPERTY + " = ? " +
  266 + AND + ModelConstants.RELATION_TYPE_GROUP_PROPERTY + " = ? " +
220 267 AND + ModelConstants.RELATION_TYPE_PROPERTY + " = ? ");
221 268 }
222 269 return findAllByToAndTypeStmt;
223 270 }
224 271
  272 +
225 273 private PreparedStatement getCheckRelationStmt() {
226 274 if (checkRelationStmt == null) {
227 275 checkRelationStmt = getSession().prepare(SELECT_COLUMNS + " " +
... ... @@ -230,36 +278,19 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
230 278 AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ? " +
231 279 AND + ModelConstants.RELATION_TO_ID_PROPERTY + " = ? " +
232 280 AND + ModelConstants.RELATION_TO_TYPE_PROPERTY + " = ? " +
  281 + AND + ModelConstants.RELATION_TYPE_GROUP_PROPERTY + " = ? " +
233 282 AND + ModelConstants.RELATION_TYPE_PROPERTY + " = ? ");
234 283 }
235 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 287 private EntityId toEntity(Row row, String uuidColumn, String typeColumn) {
248 288 return EntityIdFactory.getByTypeAndUuid(row.getString(typeColumn), row.getUUID(uuidColumn));
249 289 }
250 290
251 291 private ListenableFuture<List<EntityRelation>> executeAsyncRead(EntityId from, BoundStatement stmt) {
252 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 296 private ListenableFuture<Boolean> getBooleanListenableFuture(ResultSetFuture rsFuture) {
... ... @@ -276,4 +307,25 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
276 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 }
... ...