Commit 39591675f9a94c29d58efcc379c41babd7f1851e

Authored by Volodymyr Babak
1 parent b03cf28a

Extended Edge controller & service & dao for SQL. Added service test. NoSQL impl - TODO

Showing 25 changed files with 2016 additions and 179 deletions
@@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
15 */ 15 */
16 package org.thingsboard.server.controller; 16 package org.thingsboard.server.controller;
17 17
  18 +import com.google.common.util.concurrent.ListenableFuture;
18 import org.springframework.http.HttpStatus; 19 import org.springframework.http.HttpStatus;
19 import org.springframework.security.access.prepost.PreAuthorize; 20 import org.springframework.security.access.prepost.PreAuthorize;
20 import org.springframework.web.bind.annotation.PathVariable; 21 import org.springframework.web.bind.annotation.PathVariable;
@@ -25,14 +26,22 @@ import org.springframework.web.bind.annotation.RequestParam; @@ -25,14 +26,22 @@ import org.springframework.web.bind.annotation.RequestParam;
25 import org.springframework.web.bind.annotation.ResponseBody; 26 import org.springframework.web.bind.annotation.ResponseBody;
26 import org.springframework.web.bind.annotation.ResponseStatus; 27 import org.springframework.web.bind.annotation.ResponseStatus;
27 import org.springframework.web.bind.annotation.RestController; 28 import org.springframework.web.bind.annotation.RestController;
  29 +import org.thingsboard.server.common.data.Customer;
  30 +import org.thingsboard.server.common.data.Device;
  31 +import org.thingsboard.server.common.data.EntitySubtype;
28 import org.thingsboard.server.common.data.EntityType; 32 import org.thingsboard.server.common.data.EntityType;
29 import org.thingsboard.server.common.data.audit.ActionType; 33 import org.thingsboard.server.common.data.audit.ActionType;
  34 +import org.thingsboard.server.common.data.device.DeviceSearchQuery;
30 import org.thingsboard.server.common.data.edge.Edge; 35 import org.thingsboard.server.common.data.edge.Edge;
  36 +import org.thingsboard.server.common.data.edge.EdgeSearchQuery;
31 import org.thingsboard.server.common.data.exception.ThingsboardException; 37 import org.thingsboard.server.common.data.exception.ThingsboardException;
  38 +import org.thingsboard.server.common.data.id.CustomerId;
32 import org.thingsboard.server.common.data.id.EdgeId; 39 import org.thingsboard.server.common.data.id.EdgeId;
33 import org.thingsboard.server.common.data.id.TenantId; 40 import org.thingsboard.server.common.data.id.TenantId;
34 import org.thingsboard.server.common.data.page.TextPageData; 41 import org.thingsboard.server.common.data.page.TextPageData;
35 import org.thingsboard.server.common.data.page.TextPageLink; 42 import org.thingsboard.server.common.data.page.TextPageLink;
  43 +import org.thingsboard.server.dao.exception.IncorrectParameterException;
  44 +import org.thingsboard.server.dao.model.ModelConstants;
36 import org.thingsboard.server.service.security.model.SecurityUser; 45 import org.thingsboard.server.service.security.model.SecurityUser;
37 import org.thingsboard.server.service.security.permission.Operation; 46 import org.thingsboard.server.service.security.permission.Operation;
38 import org.thingsboard.server.service.security.permission.Resource; 47 import org.thingsboard.server.service.security.permission.Resource;
@@ -84,25 +93,6 @@ public class EdgeController extends BaseController { @@ -84,25 +93,6 @@ public class EdgeController extends BaseController {
84 } 93 }
85 } 94 }
86 95
87 -  
88 - @PreAuthorize("hasAuthority('TENANT_ADMIN')")  
89 - @RequestMapping(value = "/edges", params = {"limit"}, method = RequestMethod.GET)  
90 - @ResponseBody  
91 - public TextPageData<Edge> getEdges(  
92 - @RequestParam int limit,  
93 - @RequestParam(required = false) String textSearch,  
94 - @RequestParam(required = false) String idOffset,  
95 - @RequestParam(required = false) String textOffset) throws ThingsboardException {  
96 - try {  
97 - accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, Operation.READ);  
98 - TenantId tenantId = getCurrentUser().getTenantId();  
99 - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);  
100 - return checkNotNull(edgeService.findTenantEdges(tenantId, pageLink));  
101 - } catch (Exception e) {  
102 - throw handleException(e);  
103 - }  
104 - }  
105 -  
106 @PreAuthorize("hasAuthority('TENANT_ADMIN')") 96 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
107 @RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.DELETE) 97 @RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.DELETE)
108 @ResponseStatus(value = HttpStatus.OK) 98 @ResponseStatus(value = HttpStatus.OK)
@@ -129,35 +119,209 @@ public class EdgeController extends BaseController { @@ -129,35 +119,209 @@ public class EdgeController extends BaseController {
129 } 119 }
130 120
131 @PreAuthorize("hasAuthority('TENANT_ADMIN')") 121 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
  122 + @RequestMapping(value = "/customer/{customerId}/edge/{edgeId}", method = RequestMethod.POST)
  123 + @ResponseBody
  124 + public Edge assignEdgeToCustomer(@PathVariable("customerId") String strCustomerId,
  125 + @PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException {
  126 + checkParameter("customerId", strCustomerId);
  127 + checkParameter(EDGE_ID, strEdgeId);
  128 + try {
  129 + CustomerId customerId = new CustomerId(toUUID(strCustomerId));
  130 + Customer customer = checkCustomerId(customerId, Operation.READ);
  131 +
  132 + EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
  133 + checkEdgeId(edgeId, Operation.ASSIGN_TO_CUSTOMER);
  134 +
  135 + Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(getCurrentUser().getTenantId(), edgeId, customerId));
  136 +
  137 + logEntityAction(edgeId, savedEdge,
  138 + savedEdge.getCustomerId(),
  139 + ActionType.ASSIGNED_TO_CUSTOMER, null, strEdgeId, strCustomerId, customer.getName());
  140 +
  141 + return savedEdge;
  142 + } catch (Exception e) {
  143 + logEntityAction(emptyId(EntityType.EDGE), null,
  144 + null,
  145 + ActionType.ASSIGNED_TO_CUSTOMER, e, strEdgeId, strCustomerId);
  146 + throw handleException(e);
  147 + }
  148 + }
  149 +
  150 + @PreAuthorize("hasAuthority('TENANT_ADMIN')")
  151 + @RequestMapping(value = "/customer/edge/{edgeId}", method = RequestMethod.DELETE)
  152 + @ResponseBody
  153 + public Edge unassignEdgeFromCustomer(@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException {
  154 + checkParameter(EDGE_ID, strEdgeId);
  155 + try {
  156 + EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
  157 + Edge edge = checkEdgeId(edgeId, Operation.UNASSIGN_FROM_CUSTOMER);
  158 + if (edge.getCustomerId() == null || edge.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
  159 + throw new IncorrectParameterException("Edge isn't assigned to any customer!");
  160 + }
  161 + Customer customer = checkCustomerId(edge.getCustomerId(), Operation.READ);
  162 +
  163 + Edge savedEdge = checkNotNull(edgeService.unassignEdgeFromCustomer(getCurrentUser().getTenantId(), edgeId));
  164 +
  165 + logEntityAction(edgeId, edge,
  166 + edge.getCustomerId(),
  167 + ActionType.UNASSIGNED_FROM_CUSTOMER, null, strEdgeId, customer.getId().toString(), customer.getName());
  168 +
  169 + return savedEdge;
  170 + } catch (Exception e) {
  171 + logEntityAction(emptyId(EntityType.EDGE), null,
  172 + null,
  173 + ActionType.UNASSIGNED_FROM_CUSTOMER, e, strEdgeId);
  174 + throw handleException(e);
  175 + }
  176 + }
  177 +
  178 + @PreAuthorize("hasAuthority('TENANT_ADMIN')")
  179 + @RequestMapping(value = "/customer/public/edge/{edgeId}", method = RequestMethod.POST)
  180 + @ResponseBody
  181 + public Edge assignEdgeToPublicCustomer(@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException {
  182 + checkParameter(EDGE_ID, strEdgeId);
  183 + try {
  184 + EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
  185 + Edge edge = checkEdgeId(edgeId, Operation.ASSIGN_TO_CUSTOMER);
  186 + Customer publicCustomer = customerService.findOrCreatePublicCustomer(edge.getTenantId());
  187 + Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(getCurrentUser().getTenantId(), edgeId, publicCustomer.getId()));
  188 +
  189 + logEntityAction(edgeId, savedEdge,
  190 + savedEdge.getCustomerId(),
  191 + ActionType.ASSIGNED_TO_CUSTOMER, null, strEdgeId, publicCustomer.getId().toString(), publicCustomer.getName());
  192 +
  193 + return savedEdge;
  194 + } catch (Exception e) {
  195 + logEntityAction(emptyId(EntityType.EDGE), null,
  196 + null,
  197 + ActionType.ASSIGNED_TO_CUSTOMER, e, strEdgeId);
  198 + throw handleException(e);
  199 + }
  200 + }
  201 +
  202 + @PreAuthorize("hasAuthority('TENANT_ADMIN')")
  203 + @RequestMapping(value = "/tenant/edges", params = {"limit"}, method = RequestMethod.GET)
  204 + @ResponseBody
  205 + public TextPageData<Edge> getTenantEdges(
  206 + @RequestParam int limit,
  207 + @RequestParam(required = false) String type,
  208 + @RequestParam(required = false) String textSearch,
  209 + @RequestParam(required = false) String idOffset,
  210 + @RequestParam(required = false) String textOffset) throws ThingsboardException {
  211 + try {
  212 + TenantId tenantId = getCurrentUser().getTenantId();
  213 + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
  214 + if (type != null && type.trim().length() > 0) {
  215 + return checkNotNull(edgeService.findEdgesByTenantIdAndType(tenantId, type, pageLink));
  216 + } else {
  217 + return checkNotNull(edgeService.findEdgesByTenantId(tenantId, pageLink));
  218 + }
  219 + } catch (Exception e) {
  220 + throw handleException(e);
  221 + }
  222 + }
  223 +
  224 + @PreAuthorize("hasAuthority('TENANT_ADMIN')")
  225 + @RequestMapping(value = "/tenant/edges", params = {"edgeName"}, method = RequestMethod.GET)
  226 + @ResponseBody
  227 + public Edge getTenantEdge(
  228 + @RequestParam String edgeName) throws ThingsboardException {
  229 + try {
  230 + TenantId tenantId = getCurrentUser().getTenantId();
  231 + return checkNotNull(edgeService.findEdgeByTenantIdAndName(tenantId, edgeName));
  232 + } catch (Exception e) {
  233 + throw handleException(e);
  234 + }
  235 + }
  236 +
  237 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
  238 + @RequestMapping(value = "/customer/{customerId}/edges", params = {"limit"}, method = RequestMethod.GET)
  239 + @ResponseBody
  240 + public TextPageData<Edge> getCustomerEdges(
  241 + @PathVariable("customerId") String strCustomerId,
  242 + @RequestParam int limit,
  243 + @RequestParam(required = false) String type,
  244 + @RequestParam(required = false) String textSearch,
  245 + @RequestParam(required = false) String idOffset,
  246 + @RequestParam(required = false) String textOffset) throws ThingsboardException {
  247 + checkParameter("customerId", strCustomerId);
  248 + try {
  249 + TenantId tenantId = getCurrentUser().getTenantId();
  250 + CustomerId customerId = new CustomerId(toUUID(strCustomerId));
  251 + checkCustomerId(customerId, Operation.READ);
  252 + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
  253 + if (type != null && type.trim().length() > 0) {
  254 + return checkNotNull(edgeService.findEdgesByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
  255 + } else {
  256 + return checkNotNull(edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink));
  257 + }
  258 + } catch (Exception e) {
  259 + throw handleException(e);
  260 + }
  261 + }
  262 +
  263 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
132 @RequestMapping(value = "/edges", params = {"edgeIds"}, method = RequestMethod.GET) 264 @RequestMapping(value = "/edges", params = {"edgeIds"}, method = RequestMethod.GET)
133 @ResponseBody 265 @ResponseBody
134 public List<Edge> getEdgesByIds( 266 public List<Edge> getEdgesByIds(
135 @RequestParam("edgeIds") String[] strEdgeIds) throws ThingsboardException { 267 @RequestParam("edgeIds") String[] strEdgeIds) throws ThingsboardException {
136 checkArrayParameter("edgeIds", strEdgeIds); 268 checkArrayParameter("edgeIds", strEdgeIds);
137 try { 269 try {
138 - accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, Operation.READ);  
139 SecurityUser user = getCurrentUser(); 270 SecurityUser user = getCurrentUser();
140 TenantId tenantId = user.getTenantId(); 271 TenantId tenantId = user.getTenantId();
  272 + CustomerId customerId = user.getCustomerId();
141 List<EdgeId> edgeIds = new ArrayList<>(); 273 List<EdgeId> edgeIds = new ArrayList<>();
142 for (String strEdgeId : strEdgeIds) { 274 for (String strEdgeId : strEdgeIds) {
143 edgeIds.add(new EdgeId(toUUID(strEdgeId))); 275 edgeIds.add(new EdgeId(toUUID(strEdgeId)));
144 } 276 }
145 - List<Edge> edges = checkNotNull(edgeService.findEdgesByIdsAsync(tenantId, edgeIds).get());  
146 - return filterEdgesByReadPermission(edges); 277 + ListenableFuture<List<Edge>> edges;
  278 + if (customerId == null || customerId.isNullUid()) {
  279 + edges = edgeService.findEdgesByTenantIdAndIdsAsync(tenantId, edgeIds);
  280 + } else {
  281 + edges = edgeService.findEdgesByTenantIdCustomerIdAndIdsAsync(tenantId, customerId, edgeIds);
  282 + }
  283 + return checkNotNull(edges.get());
147 } catch (Exception e) { 284 } catch (Exception e) {
148 throw handleException(e); 285 throw handleException(e);
149 } 286 }
150 } 287 }
151 288
152 - private List<Edge> filterEdgesByReadPermission(List<Edge> edges) {  
153 - return edges.stream().filter(edge -> {  
154 - try {  
155 - accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, Operation.READ, edge.getId(), edge);  
156 - return true;  
157 - } catch (ThingsboardException e) {  
158 - return false;  
159 - }  
160 - }).collect(Collectors.toList()); 289 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
  290 + @RequestMapping(value = "/edges", method = RequestMethod.POST)
  291 + @ResponseBody
  292 + public List<Edge> findByQuery(@RequestBody EdgeSearchQuery query) throws ThingsboardException {
  293 + checkNotNull(query);
  294 + checkNotNull(query.getParameters());
  295 + checkNotNull(query.getEdgeTypes());
  296 + checkEntityId(query.getParameters().getEntityId(), Operation.READ);
  297 + try {
  298 + List<Edge> edges = checkNotNull(edgeService.findEdgesByQuery(getCurrentUser().getTenantId(), query).get());
  299 + edges = edges.stream().filter(edge -> {
  300 + try {
  301 + accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, Operation.READ, edge.getId(), edge);
  302 + return true;
  303 + } catch (ThingsboardException e) {
  304 + return false;
  305 + }
  306 + }).collect(Collectors.toList());
  307 + return edges;
  308 + } catch (Exception e) {
  309 + throw handleException(e);
  310 + }
  311 + }
  312 +
  313 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
  314 + @RequestMapping(value = "/edge/types", method = RequestMethod.GET)
  315 + @ResponseBody
  316 + public List<EntitySubtype> getEdgeTypes() throws ThingsboardException {
  317 + try {
  318 + SecurityUser user = getCurrentUser();
  319 + TenantId tenantId = user.getTenantId();
  320 + ListenableFuture<List<EntitySubtype>> edgeTypes = edgeService.findEdgeTypesByTenantId(tenantId);
  321 + return checkNotNull(edgeTypes.get());
  322 + } catch (Exception e) {
  323 + throw handleException(e);
  324 + }
161 } 325 }
162 326
163 } 327 }
@@ -29,10 +29,12 @@ import org.thingsboard.server.common.data.Device; @@ -29,10 +29,12 @@ import org.thingsboard.server.common.data.Device;
29 import org.thingsboard.server.common.data.EntityView; 29 import org.thingsboard.server.common.data.EntityView;
30 import org.thingsboard.server.common.data.Tenant; 30 import org.thingsboard.server.common.data.Tenant;
31 import org.thingsboard.server.common.data.asset.Asset; 31 import org.thingsboard.server.common.data.asset.Asset;
  32 +import org.thingsboard.server.common.data.edge.Edge;
32 import org.thingsboard.server.common.data.exception.ThingsboardException; 33 import org.thingsboard.server.common.data.exception.ThingsboardException;
33 import org.thingsboard.server.common.data.id.AssetId; 34 import org.thingsboard.server.common.data.id.AssetId;
34 import org.thingsboard.server.common.data.id.CustomerId; 35 import org.thingsboard.server.common.data.id.CustomerId;
35 import org.thingsboard.server.common.data.id.DeviceId; 36 import org.thingsboard.server.common.data.id.DeviceId;
  37 +import org.thingsboard.server.common.data.id.EdgeId;
36 import org.thingsboard.server.common.data.id.EntityId; 38 import org.thingsboard.server.common.data.id.EntityId;
37 import org.thingsboard.server.common.data.id.EntityIdFactory; 39 import org.thingsboard.server.common.data.id.EntityIdFactory;
38 import org.thingsboard.server.common.data.id.EntityViewId; 40 import org.thingsboard.server.common.data.id.EntityViewId;
@@ -46,6 +48,7 @@ import org.thingsboard.server.dao.alarm.AlarmService; @@ -46,6 +48,7 @@ import org.thingsboard.server.dao.alarm.AlarmService;
46 import org.thingsboard.server.dao.asset.AssetService; 48 import org.thingsboard.server.dao.asset.AssetService;
47 import org.thingsboard.server.dao.customer.CustomerService; 49 import org.thingsboard.server.dao.customer.CustomerService;
48 import org.thingsboard.server.dao.device.DeviceService; 50 import org.thingsboard.server.dao.device.DeviceService;
  51 +import org.thingsboard.server.dao.edge.EdgeService;
49 import org.thingsboard.server.dao.entityview.EntityViewService; 52 import org.thingsboard.server.dao.entityview.EntityViewService;
50 import org.thingsboard.server.dao.rule.RuleChainService; 53 import org.thingsboard.server.dao.rule.RuleChainService;
51 import org.thingsboard.server.dao.tenant.TenantService; 54 import org.thingsboard.server.dao.tenant.TenantService;
@@ -72,6 +75,7 @@ public class AccessValidator { @@ -72,6 +75,7 @@ public class AccessValidator {
72 public static final String CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "Customer user is not allowed to perform this operation!"; 75 public static final String CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "Customer user is not allowed to perform this operation!";
73 public static final String SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "System administrator is not allowed to perform this operation!"; 76 public static final String SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "System administrator is not allowed to perform this operation!";
74 public static final String DEVICE_WITH_REQUESTED_ID_NOT_FOUND = "Device with requested id wasn't found!"; 77 public static final String DEVICE_WITH_REQUESTED_ID_NOT_FOUND = "Device with requested id wasn't found!";
  78 + public static final String EDGE_WITH_REQUESTED_ID_NOT_FOUND = "Edge with requested id wasn't found!";
75 public static final String ENTITY_VIEW_WITH_REQUESTED_ID_NOT_FOUND = "Entity-view with requested id wasn't found!"; 79 public static final String ENTITY_VIEW_WITH_REQUESTED_ID_NOT_FOUND = "Entity-view with requested id wasn't found!";
76 80
77 @Autowired 81 @Autowired
@@ -99,6 +103,9 @@ public class AccessValidator { @@ -99,6 +103,9 @@ public class AccessValidator {
99 protected EntityViewService entityViewService; 103 protected EntityViewService entityViewService;
100 104
101 @Autowired 105 @Autowired
  106 + protected EdgeService edgeService;
  107 +
  108 + @Autowired
102 protected AccessControlService accessControlService; 109 protected AccessControlService accessControlService;
103 110
104 private ExecutorService executor; 111 private ExecutorService executor;
@@ -174,6 +181,9 @@ public class AccessValidator { @@ -174,6 +181,9 @@ public class AccessValidator {
174 case ENTITY_VIEW: 181 case ENTITY_VIEW:
175 validateEntityView(currentUser, operation, entityId, callback); 182 validateEntityView(currentUser, operation, entityId, callback);
176 return; 183 return;
  184 + case EDGE:
  185 + validateEdge(currentUser, operation, entityId, callback);
  186 + return;
177 default: 187 default:
178 //TODO: add support of other entities 188 //TODO: add support of other entities
179 throw new IllegalStateException("Not Implemented!"); 189 throw new IllegalStateException("Not Implemented!");
@@ -327,6 +337,26 @@ public class AccessValidator { @@ -327,6 +337,26 @@ public class AccessValidator {
327 } 337 }
328 } 338 }
329 339
  340 + private void validateEdge(final SecurityUser currentUser, Operation operation, EntityId entityId, FutureCallback<ValidationResult> callback) {
  341 + if (currentUser.isSystemAdmin()) {
  342 + callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
  343 + } else {
  344 + ListenableFuture<Edge> edgeFuture = edgeService.findEdgeByIdAsync(currentUser.getTenantId(), new EdgeId(entityId.getId()));
  345 + Futures.addCallback(edgeFuture, getCallback(callback, edge -> {
  346 + if (edge == null) {
  347 + return ValidationResult.entityNotFound(EDGE_WITH_REQUESTED_ID_NOT_FOUND);
  348 + } else {
  349 + try {
  350 + accessControlService.checkPermission(currentUser, Resource.EDGE, operation, entityId, edge);
  351 + } catch (ThingsboardException e) {
  352 + return ValidationResult.accessDenied(e.getMessage());
  353 + }
  354 + return ValidationResult.ok(edge);
  355 + }
  356 + }), executor);
  357 + }
  358 + }
  359 +
330 private <T, V> FutureCallback<T> getCallback(FutureCallback<ValidationResult> callback, Function<T, ValidationResult<V>> transformer) { 360 private <T, V> FutureCallback<T> getCallback(FutureCallback<ValidationResult> callback, Function<T, ValidationResult<V>> transformer) {
331 return new FutureCallback<T>() { 361 return new FutureCallback<T>() {
332 @Override 362 @Override
@@ -40,6 +40,7 @@ public class CustomerUserPermissions extends AbstractPermissions { @@ -40,6 +40,7 @@ public class CustomerUserPermissions extends AbstractPermissions {
40 put(Resource.USER, userPermissionChecker); 40 put(Resource.USER, userPermissionChecker);
41 put(Resource.WIDGETS_BUNDLE, widgetsPermissionChecker); 41 put(Resource.WIDGETS_BUNDLE, widgetsPermissionChecker);
42 put(Resource.WIDGET_TYPE, widgetsPermissionChecker); 42 put(Resource.WIDGET_TYPE, widgetsPermissionChecker);
  43 + put(Resource.EDGE, customerEntityPermissionChecker);
43 } 44 }
44 45
45 private static final PermissionChecker customerEntityPermissionChecker = 46 private static final PermissionChecker customerEntityPermissionChecker =
@@ -267,6 +267,9 @@ caffeine: @@ -267,6 +267,9 @@ caffeine:
267 entityViews: 267 entityViews:
268 timeToLiveInMinutes: 1440 268 timeToLiveInMinutes: 1440
269 maxSize: 100000 269 maxSize: 100000
  270 + edges:
  271 + timeToLiveInMinutes: 1440
  272 + maxSize: 100000
270 claimDevices: 273 claimDevices:
271 timeToLiveInMinutes: 1 274 timeToLiveInMinutes: 1
272 maxSize: 100000 275 maxSize: 100000
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 * you may not use this file except in compliance with 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 6 * You may obtain a copy of the License at
7 * 7 *
8 - * http://www.apache.org/licenses/LICENSE-2.0 8 + * http://www.apache.org/licenses/LICENSE-2.0
9 * 9 *
10 * Unless required by applicable law or agreed to in writing, software 10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, 11 * distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,39 +15,46 @@ @@ -15,39 +15,46 @@
15 */ 15 */
16 package org.thingsboard.server.controller; 16 package org.thingsboard.server.controller;
17 17
  18 +import com.datastax.driver.core.utils.UUIDs;
18 import com.fasterxml.jackson.core.type.TypeReference; 19 import com.fasterxml.jackson.core.type.TypeReference;
19 import org.apache.commons.lang3.RandomStringUtils; 20 import org.apache.commons.lang3.RandomStringUtils;
20 import org.junit.After; 21 import org.junit.After;
21 import org.junit.Assert; 22 import org.junit.Assert;
22 import org.junit.Before; 23 import org.junit.Before;
23 import org.junit.Test; 24 import org.junit.Test;
  25 +import org.thingsboard.server.common.data.Customer;
  26 +import org.thingsboard.server.common.data.EntitySubtype;
24 import org.thingsboard.server.common.data.Tenant; 27 import org.thingsboard.server.common.data.Tenant;
25 import org.thingsboard.server.common.data.User; 28 import org.thingsboard.server.common.data.User;
26 import org.thingsboard.server.common.data.edge.Edge; 29 import org.thingsboard.server.common.data.edge.Edge;
  30 +import org.thingsboard.server.common.data.id.CustomerId;
27 import org.thingsboard.server.common.data.page.TextPageData; 31 import org.thingsboard.server.common.data.page.TextPageData;
28 import org.thingsboard.server.common.data.page.TextPageLink; 32 import org.thingsboard.server.common.data.page.TextPageLink;
29 import org.thingsboard.server.common.data.security.Authority; 33 import org.thingsboard.server.common.data.security.Authority;
  34 +import org.thingsboard.server.dao.model.ModelConstants;
30 35
31 import java.util.ArrayList; 36 import java.util.ArrayList;
32 import java.util.Collections; 37 import java.util.Collections;
33 import java.util.List; 38 import java.util.List;
34 39
35 import static org.hamcrest.Matchers.containsString; 40 import static org.hamcrest.Matchers.containsString;
36 -import static org.junit.Assert.assertEquals;  
37 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 41 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
  42 +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
38 43
39 public abstract class BaseEdgeControllerTest extends AbstractControllerTest { 44 public abstract class BaseEdgeControllerTest extends AbstractControllerTest {
40 45
41 - private IdComparator<Edge> idComparator; 46 + private IdComparator<Edge> idComparator = new IdComparator<>();
  47 +
42 private Tenant savedTenant; 48 private Tenant savedTenant;
43 private User tenantAdmin; 49 private User tenantAdmin;
44 50
45 @Before 51 @Before
46 public void beforeTest() throws Exception { 52 public void beforeTest() throws Exception {
47 loginSysAdmin(); 53 loginSysAdmin();
48 - idComparator = new IdComparator<>();  
49 54
50 - savedTenant = doPost("/api/tenant", getNewTenant("My tenant"), Tenant.class); 55 + Tenant tenant = new Tenant();
  56 + tenant.setTitle("My tenant");
  57 + savedTenant = doPost("/api/tenant", tenant, Tenant.class);
51 Assert.assertNotNull(savedTenant); 58 Assert.assertNotNull(savedTenant);
52 59
53 tenantAdmin = new User(); 60 tenantAdmin = new User();
@@ -56,44 +63,88 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest { @@ -56,44 +63,88 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest {
56 tenantAdmin.setEmail("tenant2@thingsboard.org"); 63 tenantAdmin.setEmail("tenant2@thingsboard.org");
57 tenantAdmin.setFirstName("Joe"); 64 tenantAdmin.setFirstName("Joe");
58 tenantAdmin.setLastName("Downs"); 65 tenantAdmin.setLastName("Downs");
59 - tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");  
60 66
  67 + tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
61 } 68 }
62 69
63 @After 70 @After
64 public void afterTest() throws Exception { 71 public void afterTest() throws Exception {
65 loginSysAdmin(); 72 loginSysAdmin();
  73 +
66 doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) 74 doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
67 .andExpect(status().isOk()); 75 .andExpect(status().isOk());
68 } 76 }
69 77
70 @Test 78 @Test
71 - public void testFindEdgeById() throws Exception {  
72 - Edge savedEdge = getNewSavedEdge("Test edge");  
73 - Edge foundEdge = doGet("/api/edge/" + savedEdge.getId().getId().toString(), Edge.class);  
74 - Assert.assertNotNull(foundEdge);  
75 - assertEquals(savedEdge, foundEdge);  
76 - }  
77 -  
78 - @Test  
79 public void testSaveEdge() throws Exception { 79 public void testSaveEdge() throws Exception {
80 - Edge savedEdge = getNewSavedEdge("Test edge"); 80 + Edge edge = new Edge();
  81 + edge.setName("My edge");
  82 + edge.setType("default");
  83 + Edge savedEdge = doPost("/api/edge", edge, Edge.class);
81 84
82 Assert.assertNotNull(savedEdge); 85 Assert.assertNotNull(savedEdge);
83 Assert.assertNotNull(savedEdge.getId()); 86 Assert.assertNotNull(savedEdge.getId());
84 Assert.assertTrue(savedEdge.getCreatedTime() > 0); 87 Assert.assertTrue(savedEdge.getCreatedTime() > 0);
85 - assertEquals(savedTenant.getId(), savedEdge.getTenantId()); 88 + Assert.assertEquals(savedTenant.getId(), savedEdge.getTenantId());
  89 + Assert.assertNotNull(savedEdge.getCustomerId());
  90 + Assert.assertEquals(NULL_UUID, savedEdge.getCustomerId().getId());
  91 + Assert.assertEquals(edge.getName(), savedEdge.getName());
86 92
87 - savedEdge.setName("New test edge"); 93 + savedEdge.setName("My new edge");
88 doPost("/api/edge", savedEdge, Edge.class); 94 doPost("/api/edge", savedEdge, Edge.class);
  95 +
89 Edge foundEdge = doGet("/api/edge/" + savedEdge.getId().getId().toString(), Edge.class); 96 Edge foundEdge = doGet("/api/edge/" + savedEdge.getId().getId().toString(), Edge.class);
  97 + Assert.assertEquals(foundEdge.getName(), savedEdge.getName());
  98 + }
90 99
91 - assertEquals(foundEdge.getName(), savedEdge.getName()); 100 + @Test
  101 + public void testFindEdgeById() throws Exception {
  102 + Edge edge = new Edge();
  103 + edge.setName("My edge");
  104 + edge.setType("default");
  105 + Edge savedEdge = doPost("/api/edge", edge, Edge.class);
  106 + Edge foundEdge = doGet("/api/edge/" + savedEdge.getId().getId().toString(), Edge.class);
  107 + Assert.assertNotNull(foundEdge);
  108 + Assert.assertEquals(savedEdge, foundEdge);
  109 + }
  110 +
  111 + @Test
  112 + public void testFindEdgeTypesByTenantId() throws Exception {
  113 + List<Edge> edges = new ArrayList<>();
  114 + for (int i = 0; i < 3; i++) {
  115 + Edge edge = new Edge();
  116 + edge.setName("My edge B" + i);
  117 + edge.setType("typeB");
  118 + edges.add(doPost("/api/edge", edge, Edge.class));
  119 + }
  120 + for (int i = 0; i < 7; i++) {
  121 + Edge edge = new Edge();
  122 + edge.setName("My edge C" + i);
  123 + edge.setType("typeC");
  124 + edges.add(doPost("/api/edge", edge, Edge.class));
  125 + }
  126 + for (int i = 0; i < 9; i++) {
  127 + Edge edge = new Edge();
  128 + edge.setName("My edge A" + i);
  129 + edge.setType("typeA");
  130 + edges.add(doPost("/api/edge", edge, Edge.class));
  131 + }
  132 + List<EntitySubtype> edgeTypes = doGetTyped("/api/edge/types",
  133 + new TypeReference<List<EntitySubtype>>() {
  134 + });
  135 +
  136 + Assert.assertNotNull(edgeTypes);
  137 + Assert.assertEquals(3, edgeTypes.size());
  138 + Assert.assertEquals("typeA", edgeTypes.get(0).getType());
  139 + Assert.assertEquals("typeB", edgeTypes.get(1).getType());
  140 + Assert.assertEquals("typeC", edgeTypes.get(2).getType());
92 } 141 }
93 142
94 @Test 143 @Test
95 public void testDeleteEdge() throws Exception { 144 public void testDeleteEdge() throws Exception {
96 - Edge edge = getNewSavedEdge("Test edge"); 145 + Edge edge = new Edge();
  146 + edge.setName("My edge");
  147 + edge.setType("default");
97 Edge savedEdge = doPost("/api/edge", edge, Edge.class); 148 Edge savedEdge = doPost("/api/edge", edge, Edge.class);
98 149
99 doDelete("/api/edge/" + savedEdge.getId().getId().toString()) 150 doDelete("/api/edge/" + savedEdge.getId().getId().toString())
@@ -104,103 +155,523 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest { @@ -104,103 +155,523 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest {
104 } 155 }
105 156
106 @Test 157 @Test
  158 + public void testSaveEdgeWithEmptyType() throws Exception {
  159 + Edge edge = new Edge();
  160 + edge.setName("My edge");
  161 + doPost("/api/edge", edge)
  162 + .andExpect(status().isBadRequest())
  163 + .andExpect(statusReason(containsString("Edge type should be specified")));
  164 + }
  165 +
  166 + @Test
107 public void testSaveEdgeWithEmptyName() throws Exception { 167 public void testSaveEdgeWithEmptyName() throws Exception {
108 Edge edge = new Edge(); 168 Edge edge = new Edge();
  169 + edge.setType("default");
109 doPost("/api/edge", edge) 170 doPost("/api/edge", edge)
110 .andExpect(status().isBadRequest()) 171 .andExpect(status().isBadRequest())
111 - .andExpect(statusReason(containsString("Edge name should be specified!"))); 172 + .andExpect(statusReason(containsString("Edge name should be specified")));
  173 + }
  174 +
  175 + @Test
  176 + public void testAssignUnassignEdgeToCustomer() throws Exception {
  177 + Edge edge = new Edge();
  178 + edge.setName("My edge");
  179 + edge.setType("default");
  180 + Edge savedEdge = doPost("/api/edge", edge, Edge.class);
  181 +
  182 + Customer customer = new Customer();
  183 + customer.setTitle("My customer");
  184 + Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
  185 +
  186 + Edge assignedEdge = doPost("/api/customer/" + savedCustomer.getId().getId().toString()
  187 + + "/edge/" + savedEdge.getId().getId().toString(), Edge.class);
  188 + Assert.assertEquals(savedCustomer.getId(), assignedEdge.getCustomerId());
  189 +
  190 + Edge foundEdge = doGet("/api/edge/" + savedEdge.getId().getId().toString(), Edge.class);
  191 + Assert.assertEquals(savedCustomer.getId(), foundEdge.getCustomerId());
  192 +
  193 + Edge unassignedEdge =
  194 + doDelete("/api/customer/edge/" + savedEdge.getId().getId().toString(), Edge.class);
  195 + Assert.assertEquals(ModelConstants.NULL_UUID, unassignedEdge.getCustomerId().getId());
  196 +
  197 + foundEdge = doGet("/api/edge/" + savedEdge.getId().getId().toString(), Edge.class);
  198 + Assert.assertEquals(ModelConstants.NULL_UUID, foundEdge.getCustomerId().getId());
112 } 199 }
113 200
114 @Test 201 @Test
115 - public void testGetEdges() throws Exception { 202 + public void testAssignEdgeToNonExistentCustomer() throws Exception {
  203 + Edge edge = new Edge();
  204 + edge.setName("My edge");
  205 + edge.setType("default");
  206 + Edge savedEdge = doPost("/api/edge", edge, Edge.class);
116 207
  208 + doPost("/api/customer/" + UUIDs.timeBased().toString()
  209 + + "/edge/" + savedEdge.getId().getId().toString())
  210 + .andExpect(status().isNotFound());
  211 + }
  212 +
  213 + @Test
  214 + public void testAssignEdgeToCustomerFromDifferentTenant() throws Exception {
  215 + loginSysAdmin();
  216 +
  217 + Tenant tenant2 = new Tenant();
  218 + tenant2.setTitle("Different tenant");
  219 + Tenant savedTenant2 = doPost("/api/tenant", tenant2, Tenant.class);
  220 + Assert.assertNotNull(savedTenant2);
  221 +
  222 + User tenantAdmin2 = new User();
  223 + tenantAdmin2.setAuthority(Authority.TENANT_ADMIN);
  224 + tenantAdmin2.setTenantId(savedTenant2.getId());
  225 + tenantAdmin2.setEmail("tenant3@thingsboard.org");
  226 + tenantAdmin2.setFirstName("Joe");
  227 + tenantAdmin2.setLastName("Downs");
  228 +
  229 + tenantAdmin2 = createUserAndLogin(tenantAdmin2, "testPassword1");
  230 +
  231 + Customer customer = new Customer();
  232 + customer.setTitle("Different customer");
  233 + Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
  234 +
  235 + login(tenantAdmin.getEmail(), "testPassword1");
  236 +
  237 + Edge edge = new Edge();
  238 + edge.setName("My edge");
  239 + edge.setType("default");
  240 + Edge savedEdge = doPost("/api/edge", edge, Edge.class);
  241 +
  242 + doPost("/api/customer/" + savedCustomer.getId().getId().toString()
  243 + + "/edge/" + savedEdge.getId().getId().toString())
  244 + .andExpect(status().isForbidden());
  245 +
  246 + loginSysAdmin();
  247 +
  248 + doDelete("/api/tenant/" + savedTenant2.getId().getId().toString())
  249 + .andExpect(status().isOk());
  250 + }
  251 +
  252 + @Test
  253 + public void testFindTenantEdges() throws Exception {
117 List<Edge> edges = new ArrayList<>(); 254 List<Edge> edges = new ArrayList<>();
118 for (int i = 0; i < 178; i++) { 255 for (int i = 0; i < 178; i++) {
119 - edges.add(getNewSavedEdge("Test edge " + i)); 256 + Edge edge = new Edge();
  257 + edge.setName("Edge" + i);
  258 + edge.setType("default");
  259 + edges.add(doPost("/api/edge", edge, Edge.class));
120 } 260 }
121 - List<Edge> loadedEdges = loadListOf(new TextPageLink(23), "/api/edges?"); 261 + List<Edge> loadedEdges = new ArrayList<>();
  262 + TextPageLink pageLink = new TextPageLink(23);
  263 + TextPageData<Edge> pageData = null;
  264 + do {
  265 + pageData = doGetTypedWithPageLink("/api/tenant/edges?",
  266 + new TypeReference<TextPageData<Edge>>() {
  267 + }, pageLink);
  268 + loadedEdges.addAll(pageData.getData());
  269 + if (pageData.hasNext()) {
  270 + pageLink = pageData.getNextPageLink();
  271 + }
  272 + } while (pageData.hasNext());
122 273
123 Collections.sort(edges, idComparator); 274 Collections.sort(edges, idComparator);
124 Collections.sort(loadedEdges, idComparator); 275 Collections.sort(loadedEdges, idComparator);
125 276
126 - assertEquals(edges, loadedEdges); 277 + Assert.assertEquals(edges, loadedEdges);
127 } 278 }
128 279
129 @Test 280 @Test
130 - public void testGetEdgesByName() throws Exception {  
131 - String name1 = "Entity edge1";  
132 - List<Edge> namesOfEdge1 = fillListOf(143, name1);  
133 - List<Edge> loadedNamesOfEdge1 = loadListOf(new TextPageLink(15, name1), "/api/edges?");  
134 - Collections.sort(namesOfEdge1, idComparator);  
135 - Collections.sort(loadedNamesOfEdge1, idComparator);  
136 - assertEquals(namesOfEdge1, loadedNamesOfEdge1);  
137 -  
138 - String name2 = "Entity edge2";  
139 - List<Edge> namesOfEdge2 = fillListOf(75, name2);  
140 - List<Edge> loadedNamesOfEdge2 = loadListOf(new TextPageLink(4, name2), "/api/edges?");  
141 - Collections.sort(namesOfEdge2, idComparator);  
142 - Collections.sort(loadedNamesOfEdge2, idComparator);  
143 - assertEquals(namesOfEdge2, loadedNamesOfEdge2);  
144 -  
145 - for (Edge edge : loadedNamesOfEdge1) {  
146 - doDelete("/api/edge/" + edge.getId().getId().toString()).andExpect(status().isOk());  
147 - }  
148 - TextPageData<Edge> pageData = doGetTypedWithPageLink("/api/edges?", 281 + public void testFindTenantEdgesByName() throws Exception {
  282 + String title1 = "Edge title 1";
  283 + List<Edge> edgesTitle1 = new ArrayList<>();
  284 + for (int i = 0; i < 143; i++) {
  285 + Edge edge = new Edge();
  286 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  287 + String name = title1 + suffix;
  288 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  289 + edge.setName(name);
  290 + edge.setType("default");
  291 + edgesTitle1.add(doPost("/api/edge", edge, Edge.class));
  292 + }
  293 + String title2 = "Edge title 2";
  294 + List<Edge> edgesTitle2 = new ArrayList<>();
  295 + for (int i = 0; i < 75; i++) {
  296 + Edge edge = new Edge();
  297 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  298 + String name = title2 + suffix;
  299 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  300 + edge.setName(name);
  301 + edge.setType("default");
  302 + edgesTitle2.add(doPost("/api/edge", edge, Edge.class));
  303 + }
  304 +
  305 + List<Edge> loadedEdgesTitle1 = new ArrayList<>();
  306 + TextPageLink pageLink = new TextPageLink(15, title1);
  307 + TextPageData<Edge> pageData = null;
  308 + do {
  309 + pageData = doGetTypedWithPageLink("/api/tenant/edges?",
  310 + new TypeReference<TextPageData<Edge>>() {
  311 + }, pageLink);
  312 + loadedEdgesTitle1.addAll(pageData.getData());
  313 + if (pageData.hasNext()) {
  314 + pageLink = pageData.getNextPageLink();
  315 + }
  316 + } while (pageData.hasNext());
  317 +
  318 + Collections.sort(edgesTitle1, idComparator);
  319 + Collections.sort(loadedEdgesTitle1, idComparator);
  320 +
  321 + Assert.assertEquals(edgesTitle1, loadedEdgesTitle1);
  322 +
  323 + List<Edge> loadedEdgesTitle2 = new ArrayList<>();
  324 + pageLink = new TextPageLink(4, title2);
  325 + do {
  326 + pageData = doGetTypedWithPageLink("/api/tenant/edges?",
  327 + new TypeReference<TextPageData<Edge>>() {
  328 + }, pageLink);
  329 + loadedEdgesTitle2.addAll(pageData.getData());
  330 + if (pageData.hasNext()) {
  331 + pageLink = pageData.getNextPageLink();
  332 + }
  333 + } while (pageData.hasNext());
  334 +
  335 + Collections.sort(edgesTitle2, idComparator);
  336 + Collections.sort(loadedEdgesTitle2, idComparator);
  337 +
  338 + Assert.assertEquals(edgesTitle2, loadedEdgesTitle2);
  339 +
  340 + for (Edge edge : loadedEdgesTitle1) {
  341 + doDelete("/api/edge/" + edge.getId().getId().toString())
  342 + .andExpect(status().isOk());
  343 + }
  344 +
  345 + pageLink = new TextPageLink(4, title1);
  346 + pageData = doGetTypedWithPageLink("/api/tenant/edges?",
149 new TypeReference<TextPageData<Edge>>() { 347 new TypeReference<TextPageData<Edge>>() {
150 - }, new TextPageLink(4, name1)); 348 + }, pageLink);
151 Assert.assertFalse(pageData.hasNext()); 349 Assert.assertFalse(pageData.hasNext());
152 - assertEquals(0, pageData.getData().size()); 350 + Assert.assertEquals(0, pageData.getData().size());
153 351
154 - for (Edge edge : loadedNamesOfEdge2) {  
155 - doDelete("/api/edge/" + edge.getId().getId().toString()).andExpect(status().isOk()); 352 + for (Edge edge : loadedEdgesTitle2) {
  353 + doDelete("/api/edge/" + edge.getId().getId().toString())
  354 + .andExpect(status().isOk());
156 } 355 }
157 - pageData = doGetTypedWithPageLink("/api/edges?", new TypeReference<TextPageData<Edge>>() {  
158 - }, new TextPageLink(4, name2)); 356 +
  357 + pageLink = new TextPageLink(4, title2);
  358 + pageData = doGetTypedWithPageLink("/api/tenant/edges?",
  359 + new TypeReference<TextPageData<Edge>>() {
  360 + }, pageLink);
159 Assert.assertFalse(pageData.hasNext()); 361 Assert.assertFalse(pageData.hasNext());
160 - assertEquals(0, pageData.getData().size()); 362 + Assert.assertEquals(0, pageData.getData().size());
161 } 363 }
162 364
163 - private Edge getNewSavedEdge(String name) throws Exception {  
164 - Edge edge = createEdge(name);  
165 - return doPost("/api/edge", edge, Edge.class);  
166 - } 365 + @Test
  366 + public void testFindTenantEdgesByType() throws Exception {
  367 + String title1 = "Edge title 1";
  368 + String type1 = "typeA";
  369 + List<Edge> edgesType1 = new ArrayList<>();
  370 + for (int i = 0; i < 143; i++) {
  371 + Edge edge = new Edge();
  372 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  373 + String name = title1 + suffix;
  374 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  375 + edge.setName(name);
  376 + edge.setType(type1);
  377 + edgesType1.add(doPost("/api/edge", edge, Edge.class));
  378 + }
  379 + String title2 = "Edge title 2";
  380 + String type2 = "typeB";
  381 + List<Edge> edgesType2 = new ArrayList<>();
  382 + for (int i = 0; i < 75; i++) {
  383 + Edge edge = new Edge();
  384 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  385 + String name = title2 + suffix;
  386 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  387 + edge.setName(name);
  388 + edge.setType(type2);
  389 + edgesType2.add(doPost("/api/edge", edge, Edge.class));
  390 + }
167 391
168 - private Edge createEdge(String name) {  
169 - Edge edge = new Edge();  
170 - edge.setTenantId(savedTenant.getId());  
171 - edge.setName(name);  
172 - return edge; 392 + List<Edge> loadedEdgesType1 = new ArrayList<>();
  393 + TextPageLink pageLink = new TextPageLink(15);
  394 + TextPageData<Edge> pageData = null;
  395 + do {
  396 + pageData = doGetTypedWithPageLink("/api/tenant/edges?type={type}&",
  397 + new TypeReference<TextPageData<Edge>>() {
  398 + }, pageLink, type1);
  399 + loadedEdgesType1.addAll(pageData.getData());
  400 + if (pageData.hasNext()) {
  401 + pageLink = pageData.getNextPageLink();
  402 + }
  403 + } while (pageData.hasNext());
  404 +
  405 + Collections.sort(edgesType1, idComparator);
  406 + Collections.sort(loadedEdgesType1, idComparator);
  407 +
  408 + Assert.assertEquals(edgesType1, loadedEdgesType1);
  409 +
  410 + List<Edge> loadedEdgesType2 = new ArrayList<>();
  411 + pageLink = new TextPageLink(4);
  412 + do {
  413 + pageData = doGetTypedWithPageLink("/api/tenant/edges?type={type}&",
  414 + new TypeReference<TextPageData<Edge>>() {
  415 + }, pageLink, type2);
  416 + loadedEdgesType2.addAll(pageData.getData());
  417 + if (pageData.hasNext()) {
  418 + pageLink = pageData.getNextPageLink();
  419 + }
  420 + } while (pageData.hasNext());
  421 +
  422 + Collections.sort(edgesType2, idComparator);
  423 + Collections.sort(loadedEdgesType2, idComparator);
  424 +
  425 + Assert.assertEquals(edgesType2, loadedEdgesType2);
  426 +
  427 + for (Edge edge : loadedEdgesType1) {
  428 + doDelete("/api/edge/" + edge.getId().getId().toString())
  429 + .andExpect(status().isOk());
  430 + }
  431 +
  432 + pageLink = new TextPageLink(4);
  433 + pageData = doGetTypedWithPageLink("/api/tenant/edges?type={type}&",
  434 + new TypeReference<TextPageData<Edge>>() {
  435 + }, pageLink, type1);
  436 + Assert.assertFalse(pageData.hasNext());
  437 + Assert.assertEquals(0, pageData.getData().size());
  438 +
  439 + for (Edge edge : loadedEdgesType2) {
  440 + doDelete("/api/edge/" + edge.getId().getId().toString())
  441 + .andExpect(status().isOk());
  442 + }
  443 +
  444 + pageLink = new TextPageLink(4);
  445 + pageData = doGetTypedWithPageLink("/api/tenant/edges?type={type}&",
  446 + new TypeReference<TextPageData<Edge>>() {
  447 + }, pageLink, type2);
  448 + Assert.assertFalse(pageData.hasNext());
  449 + Assert.assertEquals(0, pageData.getData().size());
173 } 450 }
174 451
175 - private Tenant getNewTenant(String title) {  
176 - Tenant tenant = new Tenant();  
177 - tenant.setTitle(title);  
178 - return tenant; 452 + @Test
  453 + public void testFindCustomerEdges() throws Exception {
  454 + Customer customer = new Customer();
  455 + customer.setTitle("Test customer");
  456 + customer = doPost("/api/customer", customer, Customer.class);
  457 + CustomerId customerId = customer.getId();
  458 +
  459 + List<Edge> edges = new ArrayList<>();
  460 + for (int i = 0; i < 128; i++) {
  461 + Edge edge = new Edge();
  462 + edge.setName("Edge" + i);
  463 + edge.setType("default");
  464 + edge = doPost("/api/edge", edge, Edge.class);
  465 + edges.add(doPost("/api/customer/" + customerId.getId().toString()
  466 + + "/edge/" + edge.getId().getId().toString(), Edge.class));
  467 + }
  468 +
  469 + List<Edge> loadedEdges = new ArrayList<>();
  470 + TextPageLink pageLink = new TextPageLink(23);
  471 + TextPageData<Edge> pageData = null;
  472 + do {
  473 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?",
  474 + new TypeReference<TextPageData<Edge>>() {
  475 + }, pageLink);
  476 + loadedEdges.addAll(pageData.getData());
  477 + if (pageData.hasNext()) {
  478 + pageLink = pageData.getNextPageLink();
  479 + }
  480 + } while (pageData.hasNext());
  481 +
  482 + Collections.sort(edges, idComparator);
  483 + Collections.sort(loadedEdges, idComparator);
  484 +
  485 + Assert.assertEquals(edges, loadedEdges);
179 } 486 }
180 487
181 - private List<Edge> fillListOf(int limit, String partOfName) throws Exception {  
182 - List<Edge> edgeNames = new ArrayList<>();  
183 - for (int i = 0; i < limit; i++) {  
184 - String fullName = partOfName + ' ' + RandomStringUtils.randomAlphanumeric(15);  
185 - fullName = i % 2 == 0 ? fullName.toLowerCase() : fullName.toUpperCase();  
186 - Edge edge = getNewSavedEdge(fullName);  
187 - edgeNames.add(doPost("/api/edge", edge, Edge.class)); 488 + @Test
  489 + public void testFindCustomerEdgesByName() throws Exception {
  490 + Customer customer = new Customer();
  491 + customer.setTitle("Test customer");
  492 + customer = doPost("/api/customer", customer, Customer.class);
  493 + CustomerId customerId = customer.getId();
  494 +
  495 + String title1 = "Edge title 1";
  496 + List<Edge> edgesTitle1 = new ArrayList<>();
  497 + for (int i = 0; i < 125; i++) {
  498 + Edge edge = new Edge();
  499 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  500 + String name = title1 + suffix;
  501 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  502 + edge.setName(name);
  503 + edge.setType("default");
  504 + edge = doPost("/api/edge", edge, Edge.class);
  505 + edgesTitle1.add(doPost("/api/customer/" + customerId.getId().toString()
  506 + + "/edge/" + edge.getId().getId().toString(), Edge.class));
  507 + }
  508 + String title2 = "Edge title 2";
  509 + List<Edge> edgesTitle2 = new ArrayList<>();
  510 + for (int i = 0; i < 143; i++) {
  511 + Edge edge = new Edge();
  512 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  513 + String name = title2 + suffix;
  514 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  515 + edge.setName(name);
  516 + edge.setType("default");
  517 + edge = doPost("/api/edge", edge, Edge.class);
  518 + edgesTitle2.add(doPost("/api/customer/" + customerId.getId().toString()
  519 + + "/edge/" + edge.getId().getId().toString(), Edge.class));
  520 + }
  521 +
  522 + List<Edge> loadedEdgesTitle1 = new ArrayList<>();
  523 + TextPageLink pageLink = new TextPageLink(15, title1);
  524 + TextPageData<Edge> pageData = null;
  525 + do {
  526 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?",
  527 + new TypeReference<TextPageData<Edge>>() {
  528 + }, pageLink);
  529 + loadedEdgesTitle1.addAll(pageData.getData());
  530 + if (pageData.hasNext()) {
  531 + pageLink = pageData.getNextPageLink();
  532 + }
  533 + } while (pageData.hasNext());
  534 +
  535 + Collections.sort(edgesTitle1, idComparator);
  536 + Collections.sort(loadedEdgesTitle1, idComparator);
  537 +
  538 + Assert.assertEquals(edgesTitle1, loadedEdgesTitle1);
  539 +
  540 + List<Edge> loadedEdgesTitle2 = new ArrayList<>();
  541 + pageLink = new TextPageLink(4, title2);
  542 + do {
  543 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?",
  544 + new TypeReference<TextPageData<Edge>>() {
  545 + }, pageLink);
  546 + loadedEdgesTitle2.addAll(pageData.getData());
  547 + if (pageData.hasNext()) {
  548 + pageLink = pageData.getNextPageLink();
  549 + }
  550 + } while (pageData.hasNext());
  551 +
  552 + Collections.sort(edgesTitle2, idComparator);
  553 + Collections.sort(loadedEdgesTitle2, idComparator);
  554 +
  555 + Assert.assertEquals(edgesTitle2, loadedEdgesTitle2);
  556 +
  557 + for (Edge edge : loadedEdgesTitle1) {
  558 + doDelete("/api/customer/edge/" + edge.getId().getId().toString())
  559 + .andExpect(status().isOk());
  560 + }
  561 +
  562 + pageLink = new TextPageLink(4, title1);
  563 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?",
  564 + new TypeReference<TextPageData<Edge>>() {
  565 + }, pageLink);
  566 + Assert.assertFalse(pageData.hasNext());
  567 + Assert.assertEquals(0, pageData.getData().size());
  568 +
  569 + for (Edge edge : loadedEdgesTitle2) {
  570 + doDelete("/api/customer/edge/" + edge.getId().getId().toString())
  571 + .andExpect(status().isOk());
188 } 572 }
189 - return edgeNames; 573 +
  574 + pageLink = new TextPageLink(4, title2);
  575 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?",
  576 + new TypeReference<TextPageData<Edge>>() {
  577 + }, pageLink);
  578 + Assert.assertFalse(pageData.hasNext());
  579 + Assert.assertEquals(0, pageData.getData().size());
190 } 580 }
191 581
192 - private List<Edge> loadListOf(TextPageLink pageLink, String urlTemplate) throws Exception {  
193 - List<Edge> loadedItems = new ArrayList<>();  
194 - TextPageData<Edge> pageData; 582 + @Test
  583 + public void testFindCustomerEdgesByType() throws Exception {
  584 + Customer customer = new Customer();
  585 + customer.setTitle("Test customer");
  586 + customer = doPost("/api/customer", customer, Customer.class);
  587 + CustomerId customerId = customer.getId();
  588 +
  589 + String title1 = "Edge title 1";
  590 + String type1 = "typeC";
  591 + List<Edge> edgesType1 = new ArrayList<>();
  592 + for (int i = 0; i < 125; i++) {
  593 + Edge edge = new Edge();
  594 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  595 + String name = title1 + suffix;
  596 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  597 + edge.setName(name);
  598 + edge.setType(type1);
  599 + edge = doPost("/api/edge", edge, Edge.class);
  600 + edgesType1.add(doPost("/api/customer/" + customerId.getId().toString()
  601 + + "/edge/" + edge.getId().getId().toString(), Edge.class));
  602 + }
  603 + String title2 = "Edge title 2";
  604 + String type2 = "typeD";
  605 + List<Edge> edgesType2 = new ArrayList<>();
  606 + for (int i = 0; i < 143; i++) {
  607 + Edge edge = new Edge();
  608 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  609 + String name = title2 + suffix;
  610 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  611 + edge.setName(name);
  612 + edge.setType(type2);
  613 + edge = doPost("/api/edge", edge, Edge.class);
  614 + edgesType2.add(doPost("/api/customer/" + customerId.getId().toString()
  615 + + "/edge/" + edge.getId().getId().toString(), Edge.class));
  616 + }
  617 +
  618 + List<Edge> loadedEdgesType1 = new ArrayList<>();
  619 + TextPageLink pageLink = new TextPageLink(15);
  620 + TextPageData<Edge> pageData = null;
  621 + do {
  622 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?type={type}&",
  623 + new TypeReference<TextPageData<Edge>>() {
  624 + }, pageLink, type1);
  625 + loadedEdgesType1.addAll(pageData.getData());
  626 + if (pageData.hasNext()) {
  627 + pageLink = pageData.getNextPageLink();
  628 + }
  629 + } while (pageData.hasNext());
  630 +
  631 + Collections.sort(edgesType1, idComparator);
  632 + Collections.sort(loadedEdgesType1, idComparator);
  633 +
  634 + Assert.assertEquals(edgesType1, loadedEdgesType1);
  635 +
  636 + List<Edge> loadedEdgesType2 = new ArrayList<>();
  637 + pageLink = new TextPageLink(4);
195 do { 638 do {
196 - pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference<TextPageData<Edge>>() {  
197 - }, pageLink);  
198 - loadedItems.addAll(pageData.getData()); 639 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?type={type}&",
  640 + new TypeReference<TextPageData<Edge>>() {
  641 + }, pageLink, type2);
  642 + loadedEdgesType2.addAll(pageData.getData());
199 if (pageData.hasNext()) { 643 if (pageData.hasNext()) {
200 pageLink = pageData.getNextPageLink(); 644 pageLink = pageData.getNextPageLink();
201 } 645 }
202 } while (pageData.hasNext()); 646 } while (pageData.hasNext());
203 647
204 - return loadedItems; 648 + Collections.sort(edgesType2, idComparator);
  649 + Collections.sort(loadedEdgesType2, idComparator);
  650 +
  651 + Assert.assertEquals(edgesType2, loadedEdgesType2);
  652 +
  653 + for (Edge edge : loadedEdgesType1) {
  654 + doDelete("/api/customer/edge/" + edge.getId().getId().toString())
  655 + .andExpect(status().isOk());
  656 + }
  657 +
  658 + pageLink = new TextPageLink(4);
  659 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?type={type}&",
  660 + new TypeReference<TextPageData<Edge>>() {
  661 + }, pageLink, type1);
  662 + Assert.assertFalse(pageData.hasNext());
  663 + Assert.assertEquals(0, pageData.getData().size());
  664 +
  665 + for (Edge edge : loadedEdgesType2) {
  666 + doDelete("/api/customer/edge/" + edge.getId().getId().toString())
  667 + .andExpect(status().isOk());
  668 + }
  669 +
  670 + pageLink = new TextPageLink(4);
  671 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?type={type}&",
  672 + new TypeReference<TextPageData<Edge>>() {
  673 + }, pageLink, type2);
  674 + Assert.assertFalse(pageData.hasNext());
  675 + Assert.assertEquals(0, pageData.getData().size());
205 } 676 }
206 } 677 }
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 * you may not use this file except in compliance with 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 6 * You may obtain a copy of the License at
7 * 7 *
8 - * http://www.apache.org/licenses/LICENSE-2.0 8 + * http://www.apache.org/licenses/LICENSE-2.0
9 * 9 *
10 * Unless required by applicable law or agreed to in writing, software 10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, 11 * distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,7 +16,10 @@ @@ -16,7 +16,10 @@
16 package org.thingsboard.server.dao.edge; 16 package org.thingsboard.server.dao.edge;
17 17
18 import com.google.common.util.concurrent.ListenableFuture; 18 import com.google.common.util.concurrent.ListenableFuture;
  19 +import org.thingsboard.server.common.data.EntitySubtype;
19 import org.thingsboard.server.common.data.edge.Edge; 20 import org.thingsboard.server.common.data.edge.Edge;
  21 +import org.thingsboard.server.common.data.edge.EdgeSearchQuery;
  22 +import org.thingsboard.server.common.data.id.CustomerId;
20 import org.thingsboard.server.common.data.id.EdgeId; 23 import org.thingsboard.server.common.data.id.EdgeId;
21 import org.thingsboard.server.common.data.id.TenantId; 24 import org.thingsboard.server.common.data.id.TenantId;
22 import org.thingsboard.server.common.data.page.TextPageData; 25 import org.thingsboard.server.common.data.page.TextPageData;
@@ -26,20 +29,49 @@ import java.util.List; @@ -26,20 +29,49 @@ import java.util.List;
26 29
27 public interface EdgeService { 30 public interface EdgeService {
28 31
29 - Edge saveEdge(Edge edge);  
30 -  
31 Edge findEdgeById(TenantId tenantId, EdgeId edgeId); 32 Edge findEdgeById(TenantId tenantId, EdgeId edgeId);
32 33
33 ListenableFuture<Edge> findEdgeByIdAsync(TenantId tenantId, EdgeId edgeId); 34 ListenableFuture<Edge> findEdgeByIdAsync(TenantId tenantId, EdgeId edgeId);
34 35
35 - ListenableFuture<List<Edge>> findEdgesByIdsAsync(TenantId tenantId, List<EdgeId> edgeIds); 36 + Edge findEdgeByTenantIdAndName(TenantId tenantId, String name);
36 37
37 - List<Edge> findAllEdges(TenantId tenantId); 38 + Edge saveEdge(Edge edge);
38 39
39 - TextPageData<Edge> findTenantEdges(TenantId tenantId, TextPageLink pageLink); 40 + Edge assignEdgeToCustomer(TenantId tenantId, EdgeId edgeId, CustomerId customerId);
  41 +
  42 + Edge unassignEdgeFromCustomer(TenantId tenantId, EdgeId edgeId);
40 43
41 void deleteEdge(TenantId tenantId, EdgeId edgeId); 44 void deleteEdge(TenantId tenantId, EdgeId edgeId);
42 45
  46 + TextPageData<Edge> findEdgesByTenantId(TenantId tenantId, TextPageLink pageLink);
  47 +
  48 + TextPageData<Edge> findEdgesByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink);
  49 +
  50 + ListenableFuture<List<Edge>> findEdgesByTenantIdAndIdsAsync(TenantId tenantId, List<EdgeId> edgeIds);
  51 +
43 void deleteEdgesByTenantId(TenantId tenantId); 52 void deleteEdgesByTenantId(TenantId tenantId);
44 53
  54 + TextPageData<Edge> findEdgesByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink);
  55 +
  56 + TextPageData<Edge> findEdgesByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, TextPageLink pageLink);
  57 +
  58 + ListenableFuture<List<Edge>> findEdgesByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<EdgeId> edgeIds);
  59 +
  60 + void unassignCustomerEdges(TenantId tenantId, CustomerId customerId);
  61 +
  62 + ListenableFuture<List<Edge>> findEdgesByQuery(TenantId tenantId, EdgeSearchQuery query);
  63 +
  64 + ListenableFuture<List<EntitySubtype>> findEdgeTypesByTenantId(TenantId tenantId);
  65 +
45 } 66 }
  67 +
  68 +
  69 +
  70 +
  71 +
  72 +
  73 +
  74 +
  75 +
  76 +
  77 +
@@ -22,6 +22,7 @@ public class CacheConstants { @@ -22,6 +22,7 @@ public class CacheConstants {
22 public static final String SESSIONS_CACHE = "sessions"; 22 public static final String SESSIONS_CACHE = "sessions";
23 public static final String ASSET_CACHE = "assets"; 23 public static final String ASSET_CACHE = "assets";
24 public static final String ENTITY_VIEW_CACHE = "entityViews"; 24 public static final String ENTITY_VIEW_CACHE = "entityViews";
  25 + public static final String EDGE_CACHE = "edges";
25 public static final String CLAIM_DEVICES_CACHE = "claimDevices"; 26 public static final String CLAIM_DEVICES_CACHE = "claimDevices";
26 public static final String SECURITY_SETTINGS_CACHE = "securitySettings"; 27 public static final String SECURITY_SETTINGS_CACHE = "securitySettings";
27 } 28 }
@@ -39,6 +39,7 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H @@ -39,6 +39,7 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H
39 private TenantId tenantId; 39 private TenantId tenantId;
40 private CustomerId customerId; 40 private CustomerId customerId;
41 private String name; 41 private String name;
  42 + private String type;
42 private transient JsonNode configuration; 43 private transient JsonNode configuration;
43 private transient JsonNode additionalInfo; 44 private transient JsonNode additionalInfo;
44 45
@@ -54,6 +55,7 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H @@ -54,6 +55,7 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H
54 super(edge); 55 super(edge);
55 this.tenantId = edge.getTenantId(); 56 this.tenantId = edge.getTenantId();
56 this.customerId = edge.getCustomerId(); 57 this.customerId = edge.getCustomerId();
  58 + this.type = edge.getType();
57 this.name = edge.getName(); 59 this.name = edge.getName();
58 this.configuration = edge.getConfiguration(); 60 this.configuration = edge.getConfiguration();
59 this.additionalInfo = edge.getAdditionalInfo(); 61 this.additionalInfo = edge.getAdditionalInfo();
  1 +/**
  2 + * Copyright © 2016-2019 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.edge;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.EntityType;
  20 +import org.thingsboard.server.common.data.relation.EntityRelation;
  21 +import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
  22 +import org.thingsboard.server.common.data.relation.EntityTypeFilter;
  23 +import org.thingsboard.server.common.data.relation.RelationsSearchParameters;
  24 +
  25 +import java.util.Collections;
  26 +import java.util.List;
  27 +
  28 +@Data
  29 +public class EdgeSearchQuery {
  30 +
  31 + private RelationsSearchParameters parameters;
  32 + private String relationType;
  33 + private List<String> edgeTypes;
  34 +
  35 + public EntityRelationsQuery toEntitySearchQuery() {
  36 + EntityRelationsQuery query = new EntityRelationsQuery();
  37 + query.setParameters(parameters);
  38 + query.setFilters(
  39 + Collections.singletonList(new EntityTypeFilter(relationType == null ? EntityRelation.CONTAINS_TYPE : relationType,
  40 + Collections.singletonList(EntityType.EDGE))));
  41 + return query;
  42 + }
  43 +}
@@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.page.TextPageLink; @@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.page.TextPageLink;
31 import org.thingsboard.server.dao.asset.AssetService; 31 import org.thingsboard.server.dao.asset.AssetService;
32 import org.thingsboard.server.dao.dashboard.DashboardService; 32 import org.thingsboard.server.dao.dashboard.DashboardService;
33 import org.thingsboard.server.dao.device.DeviceService; 33 import org.thingsboard.server.dao.device.DeviceService;
  34 +import org.thingsboard.server.dao.edge.EdgeService;
34 import org.thingsboard.server.dao.entity.AbstractEntityService; 35 import org.thingsboard.server.dao.entity.AbstractEntityService;
35 import org.thingsboard.server.dao.entityview.EntityViewService; 36 import org.thingsboard.server.dao.entityview.EntityViewService;
36 import org.thingsboard.server.dao.exception.DataValidationException; 37 import org.thingsboard.server.dao.exception.DataValidationException;
@@ -76,6 +77,9 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom @@ -76,6 +77,9 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
76 @Autowired 77 @Autowired
77 private DashboardService dashboardService; 78 private DashboardService dashboardService;
78 79
  80 + @Autowired
  81 + private EdgeService edgeService;
  82 +
79 @Override 83 @Override
80 public Customer findCustomerById(TenantId tenantId, CustomerId customerId) { 84 public Customer findCustomerById(TenantId tenantId, CustomerId customerId) {
81 log.trace("Executing findCustomerById [{}]", customerId); 85 log.trace("Executing findCustomerById [{}]", customerId);
@@ -118,6 +122,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom @@ -118,6 +122,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
118 entityViewService.unassignCustomerEntityViews(customer.getTenantId(), customerId); 122 entityViewService.unassignCustomerEntityViews(customer.getTenantId(), customerId);
119 assetService.unassignCustomerAssets(customer.getTenantId(), customerId); 123 assetService.unassignCustomerAssets(customer.getTenantId(), customerId);
120 deviceService.unassignCustomerDevices(customer.getTenantId(), customerId); 124 deviceService.unassignCustomerDevices(customer.getTenantId(), customerId);
  125 + edgeService.unassignCustomerEdges(customer.getTenantId(), customerId);
121 userService.deleteCustomerUsers(customer.getTenantId(), customerId); 126 userService.deleteCustomerUsers(customer.getTenantId(), customerId);
122 deleteEntityRelations(tenantId, customerId); 127 deleteEntityRelations(tenantId, customerId);
123 customerDao.removeById(tenantId, customerId.getId()); 128 customerDao.removeById(tenantId, customerId.getId());
@@ -15,29 +15,53 @@ @@ -15,29 +15,53 @@
15 */ 15 */
16 package org.thingsboard.server.dao.edge; 16 package org.thingsboard.server.dao.edge;
17 17
  18 +import com.google.common.base.Function;
  19 +import com.google.common.util.concurrent.Futures;
18 import com.google.common.util.concurrent.ListenableFuture; 20 import com.google.common.util.concurrent.ListenableFuture;
19 import lombok.extern.slf4j.Slf4j; 21 import lombok.extern.slf4j.Slf4j;
20 import org.springframework.beans.factory.annotation.Autowired; 22 import org.springframework.beans.factory.annotation.Autowired;
  23 +import org.springframework.cache.Cache;
  24 +import org.springframework.cache.CacheManager;
  25 +import org.springframework.cache.annotation.CacheEvict;
  26 +import org.springframework.cache.annotation.Cacheable;
21 import org.springframework.stereotype.Service; 27 import org.springframework.stereotype.Service;
22 import org.springframework.util.StringUtils; 28 import org.springframework.util.StringUtils;
  29 +import org.thingsboard.server.common.data.Customer;
  30 +import org.thingsboard.server.common.data.EntitySubtype;
  31 +import org.thingsboard.server.common.data.EntityType;
23 import org.thingsboard.server.common.data.Tenant; 32 import org.thingsboard.server.common.data.Tenant;
24 import org.thingsboard.server.common.data.edge.Edge; 33 import org.thingsboard.server.common.data.edge.Edge;
  34 +import org.thingsboard.server.common.data.edge.EdgeSearchQuery;
  35 +import org.thingsboard.server.common.data.id.CustomerId;
25 import org.thingsboard.server.common.data.id.EdgeId; 36 import org.thingsboard.server.common.data.id.EdgeId;
  37 +import org.thingsboard.server.common.data.id.EntityId;
26 import org.thingsboard.server.common.data.id.TenantId; 38 import org.thingsboard.server.common.data.id.TenantId;
27 import org.thingsboard.server.common.data.page.TextPageData; 39 import org.thingsboard.server.common.data.page.TextPageData;
28 import org.thingsboard.server.common.data.page.TextPageLink; 40 import org.thingsboard.server.common.data.page.TextPageLink;
  41 +import org.thingsboard.server.common.data.relation.EntityRelation;
  42 +import org.thingsboard.server.common.data.relation.EntitySearchDirection;
  43 +import org.thingsboard.server.dao.customer.CustomerDao;
29 import org.thingsboard.server.dao.entity.AbstractEntityService; 44 import org.thingsboard.server.dao.entity.AbstractEntityService;
30 import org.thingsboard.server.dao.exception.DataValidationException; 45 import org.thingsboard.server.dao.exception.DataValidationException;
31 import org.thingsboard.server.dao.service.DataValidator; 46 import org.thingsboard.server.dao.service.DataValidator;
32 import org.thingsboard.server.dao.service.PaginatedRemover; 47 import org.thingsboard.server.dao.service.PaginatedRemover;
33 import org.thingsboard.server.dao.tenant.TenantDao; 48 import org.thingsboard.server.dao.tenant.TenantDao;
34 49
  50 +import javax.annotation.Nullable;
  51 +import java.util.ArrayList;
  52 +import java.util.Collections;
  53 +import java.util.Comparator;
35 import java.util.List; 54 import java.util.List;
  55 +import java.util.Optional;
  56 +import java.util.stream.Collectors;
36 57
  58 +import static org.thingsboard.server.common.data.CacheConstants.EDGE_CACHE;
37 import static org.thingsboard.server.dao.DaoUtil.toUUIDs; 59 import static org.thingsboard.server.dao.DaoUtil.toUUIDs;
  60 +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
38 import static org.thingsboard.server.dao.service.Validator.validateId; 61 import static org.thingsboard.server.dao.service.Validator.validateId;
39 import static org.thingsboard.server.dao.service.Validator.validateIds; 62 import static org.thingsboard.server.dao.service.Validator.validateIds;
40 import static org.thingsboard.server.dao.service.Validator.validatePageLink; 63 import static org.thingsboard.server.dao.service.Validator.validatePageLink;
  64 +import static org.thingsboard.server.dao.service.Validator.validateString;
41 65
42 @Service 66 @Service
43 @Slf4j 67 @Slf4j
@@ -45,6 +69,7 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic @@ -45,6 +69,7 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic
45 69
46 public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; 70 public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
47 public static final String INCORRECT_PAGE_LINK = "Incorrect page link "; 71 public static final String INCORRECT_PAGE_LINK = "Incorrect page link ";
  72 + public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId ";
48 public static final String INCORRECT_EDGE_ID = "Incorrect edgeId "; 73 public static final String INCORRECT_EDGE_ID = "Incorrect edgeId ";
49 74
50 @Autowired 75 @Autowired
@@ -53,12 +78,11 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic @@ -53,12 +78,11 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic
53 @Autowired 78 @Autowired
54 private TenantDao tenantDao; 79 private TenantDao tenantDao;
55 80
56 - @Override  
57 - public Edge saveEdge(Edge edge) {  
58 - log.trace("Executing saveEdge [{}]", edge);  
59 - edgeValidator.validate(edge, Edge::getTenantId);  
60 - return edgeDao.save(edge.getTenantId(), edge);  
61 - } 81 + @Autowired
  82 + private CustomerDao customerDao;
  83 +
  84 + @Autowired
  85 + private CacheManager cacheManager;
62 86
63 @Override 87 @Override
64 public Edge findEdgeById(TenantId tenantId, EdgeId edgeId) { 88 public Edge findEdgeById(TenantId tenantId, EdgeId edgeId) {
@@ -69,73 +93,222 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic @@ -69,73 +93,222 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic
69 93
70 @Override 94 @Override
71 public ListenableFuture<Edge> findEdgeByIdAsync(TenantId tenantId, EdgeId edgeId) { 95 public ListenableFuture<Edge> findEdgeByIdAsync(TenantId tenantId, EdgeId edgeId) {
72 - log.trace("Executing findEdgeByIdAsync [{}]", edgeId); 96 + log.trace("Executing findEdgeById [{}]", edgeId);
73 validateId(edgeId, INCORRECT_EDGE_ID + edgeId); 97 validateId(edgeId, INCORRECT_EDGE_ID + edgeId);
74 return edgeDao.findByIdAsync(tenantId, edgeId.getId()); 98 return edgeDao.findByIdAsync(tenantId, edgeId.getId());
75 } 99 }
76 100
  101 + @Cacheable(cacheNames = EDGE_CACHE, key = "{#tenantId, #name}")
77 @Override 102 @Override
78 - public ListenableFuture<List<Edge>> findEdgesByIdsAsync(TenantId tenantId, List<EdgeId> edgeIds) {  
79 - log.trace("Executing findEdgesByIdsAsync, tenantId [{}], edgeIds [{}]", tenantId, edgeIds); 103 + public Edge findEdgeByTenantIdAndName(TenantId tenantId, String name) {
  104 + log.trace("Executing findEdgeByTenantIdAndName [{}][{}]", tenantId, name);
80 validateId(tenantId, INCORRECT_TENANT_ID + tenantId); 105 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
81 - validateIds(edgeIds, "Incorrect edgeIds " + edgeIds);  
82 - return edgeDao.findEdgesByTenantIdAndIdsAsync(tenantId.getId(), toUUIDs(edgeIds)); 106 + Optional<Edge> edgeOpt = edgeDao.findEdgeByTenantIdAndName(tenantId.getId(), name);
  107 + return edgeOpt.orElse(null);
83 } 108 }
84 109
  110 + @CacheEvict(cacheNames = EDGE_CACHE, key = "{#edge.tenantId, #edge.name}")
85 @Override 111 @Override
86 - public List<Edge> findAllEdges(TenantId tenantId) {  
87 - log.trace("Executing findAllEdges");  
88 - return edgeDao.find(tenantId); 112 + public Edge saveEdge(Edge edge) {
  113 + log.trace("Executing saveEdge [{}]", edge);
  114 + edgeValidator.validate(edge, Edge::getTenantId);
  115 + return edgeDao.save(edge.getTenantId(), edge);
89 } 116 }
90 117
91 @Override 118 @Override
92 - public TextPageData<Edge> findTenantEdges(TenantId tenantId, TextPageLink pageLink) {  
93 - log.trace("Executing findTenantEdges, tenantId [{}], pageLink [{}]", tenantId, pageLink);  
94 - validateId(tenantId, INCORRECT_TENANT_ID + tenantId);  
95 - validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink);  
96 - List<Edge> edges = edgeDao.findByTenantIdAndPageLink(tenantId.getId(), pageLink);  
97 - return new TextPageData<>(edges, pageLink); 119 + public Edge assignEdgeToCustomer(TenantId tenantId, EdgeId edgeId, CustomerId customerId) {
  120 + Edge edge = findEdgeById(tenantId, edgeId);
  121 + edge.setCustomerId(customerId);
  122 + return saveEdge(edge);
  123 + }
  124 +
  125 + @Override
  126 + public Edge unassignEdgeFromCustomer(TenantId tenantId, EdgeId edgeId) {
  127 + Edge edge = findEdgeById(tenantId, edgeId);
  128 + edge.setCustomerId(null);
  129 + return saveEdge(edge);
98 } 130 }
99 131
100 @Override 132 @Override
101 public void deleteEdge(TenantId tenantId, EdgeId edgeId) { 133 public void deleteEdge(TenantId tenantId, EdgeId edgeId) {
102 log.trace("Executing deleteEdge [{}]", edgeId); 134 log.trace("Executing deleteEdge [{}]", edgeId);
103 validateId(edgeId, INCORRECT_EDGE_ID + edgeId); 135 validateId(edgeId, INCORRECT_EDGE_ID + edgeId);
  136 +
  137 + Edge edge = edgeDao.findById(tenantId, edgeId.getId());
  138 +
104 deleteEntityRelations(tenantId, edgeId); 139 deleteEntityRelations(tenantId, edgeId);
  140 +
  141 + List<Object> list = new ArrayList<>();
  142 + list.add(edge.getTenantId());
  143 + list.add(edge.getName());
  144 + Cache cache = cacheManager.getCache(EDGE_CACHE);
  145 + cache.evict(list);
  146 +
105 edgeDao.removeById(tenantId, edgeId.getId()); 147 edgeDao.removeById(tenantId, edgeId.getId());
106 } 148 }
107 149
108 @Override 150 @Override
  151 + public TextPageData<Edge> findEdgesByTenantId(TenantId tenantId, TextPageLink pageLink) {
  152 + log.trace("Executing findEdgesByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink);
  153 + validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
  154 + validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink);
  155 + List<Edge> edges = edgeDao.findEdgesByTenantId(tenantId.getId(), pageLink);
  156 + return new TextPageData<>(edges, pageLink);
  157 + }
  158 +
  159 + @Override
  160 + public TextPageData<Edge> findEdgesByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink) {
  161 + log.trace("Executing findEdgesByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink);
  162 + validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
  163 + validateString(type, "Incorrect type " + type);
  164 + validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink);
  165 + List<Edge> edges = edgeDao.findEdgesByTenantIdAndType(tenantId.getId(), type, pageLink);
  166 + return new TextPageData<>(edges, pageLink);
  167 + }
  168 +
  169 + @Override
  170 + public ListenableFuture<List<Edge>> findEdgesByTenantIdAndIdsAsync(TenantId tenantId, List<EdgeId> edgeIds) {
  171 + log.trace("Executing findEdgesByTenantIdAndIdsAsync, tenantId [{}], edgeIds [{}]", tenantId, edgeIds);
  172 + validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
  173 + validateIds(edgeIds, "Incorrect edgeIds " + edgeIds);
  174 + return edgeDao.findEdgesByTenantIdAndIdsAsync(tenantId.getId(), toUUIDs(edgeIds));
  175 + }
  176 +
  177 +
  178 + @Override
109 public void deleteEdgesByTenantId(TenantId tenantId) { 179 public void deleteEdgesByTenantId(TenantId tenantId) {
110 log.trace("Executing deleteEdgesByTenantId, tenantId [{}]", tenantId); 180 log.trace("Executing deleteEdgesByTenantId, tenantId [{}]", tenantId);
111 validateId(tenantId, INCORRECT_TENANT_ID + tenantId); 181 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
112 tenantEdgesRemover.removeEntities(tenantId, tenantId); 182 tenantEdgesRemover.removeEntities(tenantId, tenantId);
113 } 183 }
114 184
  185 + @Override
  186 + public TextPageData<Edge> findEdgesByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink) {
  187 + log.trace("Executing findEdgesByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink);
  188 + validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
  189 + validateId(customerId, INCORRECT_CUSTOMER_ID + customerId);
  190 + validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink);
  191 + List<Edge> edges = edgeDao.findEdgesByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink);
  192 + return new TextPageData<>(edges, pageLink);
  193 + }
  194 +
  195 + @Override
  196 + public TextPageData<Edge> findEdgesByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, TextPageLink pageLink) {
  197 + log.trace("Executing findEdgesByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}], type [{}], pageLink [{}]", tenantId, customerId, type, pageLink);
  198 + validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
  199 + validateId(customerId, INCORRECT_CUSTOMER_ID + customerId);
  200 + validateString(type, "Incorrect type " + type);
  201 + validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink);
  202 + List<Edge> edges = edgeDao.findEdgesByTenantIdAndCustomerIdAndType(tenantId.getId(), customerId.getId(), type, pageLink);
  203 + return new TextPageData<>(edges, pageLink);
  204 + }
  205 +
  206 + @Override
  207 + public ListenableFuture<List<Edge>> findEdgesByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<EdgeId> edgeIds) {
  208 + log.trace("Executing findEdgesByTenantIdCustomerIdAndIdsAsync, tenantId [{}], customerId [{}], edgeIds [{}]", tenantId, customerId, edgeIds);
  209 + validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
  210 + validateId(customerId, INCORRECT_CUSTOMER_ID + customerId);
  211 + validateIds(edgeIds, "Incorrect edgeIds " + edgeIds);
  212 + return edgeDao.findEdgesByTenantIdCustomerIdAndIdsAsync(tenantId.getId(),
  213 + customerId.getId(), toUUIDs(edgeIds));
  214 + }
  215 +
  216 + @Override
  217 + public void unassignCustomerEdges(TenantId tenantId, CustomerId customerId) {
  218 + log.trace("Executing unassignCustomerEdges, tenantId [{}], customerId [{}]", tenantId, customerId);
  219 + validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
  220 + validateId(customerId, INCORRECT_CUSTOMER_ID + customerId);
  221 + customerEdgeUnasigner.removeEntities(tenantId, customerId);
  222 + }
  223 +
  224 + @Override
  225 + public ListenableFuture<List<Edge>> findEdgesByQuery(TenantId tenantId, EdgeSearchQuery query) {
  226 + ListenableFuture<List<EntityRelation>> relations = relationService.findByQuery(tenantId, query.toEntitySearchQuery());
  227 + ListenableFuture<List<Edge>> edges = Futures.transformAsync(relations, r -> {
  228 + EntitySearchDirection direction = query.toEntitySearchQuery().getParameters().getDirection();
  229 + List<ListenableFuture<Edge>> futures = new ArrayList<>();
  230 + for (EntityRelation relation : r) {
  231 + EntityId entityId = direction == EntitySearchDirection.FROM ? relation.getTo() : relation.getFrom();
  232 + if (entityId.getEntityType() == EntityType.EDGE) {
  233 + futures.add(findEdgeByIdAsync(tenantId, new EdgeId(entityId.getId())));
  234 + }
  235 + }
  236 + return Futures.successfulAsList(futures);
  237 + });
  238 +
  239 + edges = Futures.transform(edges, new Function<List<Edge>, List<Edge>>() {
  240 + @Nullable
  241 + @Override
  242 + public List<Edge> apply(@Nullable List<Edge> edgeList) {
  243 + return edgeList == null ? Collections.emptyList() : edgeList.stream().filter(edge -> query.getEdgeTypes().contains(edge.getType())).collect(Collectors.toList());
  244 + }
  245 + });
  246 +
  247 + return edges;
  248 + }
  249 +
  250 + @Override
  251 + public ListenableFuture<List<EntitySubtype>> findEdgeTypesByTenantId(TenantId tenantId) {
  252 + log.trace("Executing findEdgeTypesByTenantId, tenantId [{}]", tenantId);
  253 + validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
  254 + ListenableFuture<List<EntitySubtype>> tenantEdgeTypes = edgeDao.findTenantEdgeTypesAsync(tenantId.getId());
  255 + return Futures.transform(tenantEdgeTypes,
  256 + edgeTypes -> {
  257 + edgeTypes.sort(Comparator.comparing(EntitySubtype::getType));
  258 + return edgeTypes;
  259 + });
  260 + }
  261 +
115 private DataValidator<Edge> edgeValidator = 262 private DataValidator<Edge> edgeValidator =
116 new DataValidator<Edge>() { 263 new DataValidator<Edge>() {
117 264
118 @Override 265 @Override
119 protected void validateCreate(TenantId tenantId, Edge edge) { 266 protected void validateCreate(TenantId tenantId, Edge edge) {
  267 + edgeDao.findEdgeByTenantIdAndName(edge.getTenantId().getId(), edge.getName()).ifPresent(
  268 + d -> {
  269 + throw new DataValidationException("Edge with such name already exists!");
  270 + }
  271 + );
120 } 272 }
121 273
122 @Override 274 @Override
123 protected void validateUpdate(TenantId tenantId, Edge edge) { 275 protected void validateUpdate(TenantId tenantId, Edge edge) {
  276 + edgeDao.findEdgeByTenantIdAndName(edge.getTenantId().getId(), edge.getName()).ifPresent(
  277 + e -> {
  278 + if (!e.getUuidId().equals(edge.getUuidId())) {
  279 + throw new DataValidationException("Edge with such name already exists!");
  280 + }
  281 + }
  282 + );
124 } 283 }
125 284
126 @Override 285 @Override
127 protected void validateDataImpl(TenantId tenantId, Edge edge) { 286 protected void validateDataImpl(TenantId tenantId, Edge edge) {
  287 + if (StringUtils.isEmpty(edge.getType())) {
  288 + throw new DataValidationException("Edge type should be specified!");
  289 + }
128 if (StringUtils.isEmpty(edge.getName())) { 290 if (StringUtils.isEmpty(edge.getName())) {
129 throw new DataValidationException("Edge name should be specified!"); 291 throw new DataValidationException("Edge name should be specified!");
130 } 292 }
131 - if (edge.getTenantId() == null || edge.getTenantId().isNullUid()) { 293 + if (edge.getTenantId() == null) {
132 throw new DataValidationException("Edge should be assigned to tenant!"); 294 throw new DataValidationException("Edge should be assigned to tenant!");
133 } else { 295 } else {
134 - Tenant tenant = tenantDao.findById(tenantId, edge.getTenantId().getId()); 296 + Tenant tenant = tenantDao.findById(edge.getTenantId(), edge.getTenantId().getId());
135 if (tenant == null) { 297 if (tenant == null) {
136 throw new DataValidationException("Edge is referencing to non-existent tenant!"); 298 throw new DataValidationException("Edge is referencing to non-existent tenant!");
137 } 299 }
138 } 300 }
  301 + if (edge.getCustomerId() == null) {
  302 + edge.setCustomerId(new CustomerId(NULL_UUID));
  303 + } else if (!edge.getCustomerId().getId().equals(NULL_UUID)) {
  304 + Customer customer = customerDao.findById(edge.getTenantId(), edge.getCustomerId().getId());
  305 + if (customer == null) {
  306 + throw new DataValidationException("Can't assign edge to non-existent customer!");
  307 + }
  308 + if (!customer.getTenantId().getId().equals(edge.getTenantId().getId())) {
  309 + throw new DataValidationException("Can't assign edge to customer from different tenant!");
  310 + }
  311 + }
139 } 312 }
140 }; 313 };
141 314
@@ -144,13 +317,26 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic @@ -144,13 +317,26 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic
144 317
145 @Override 318 @Override
146 protected List<Edge> findEntities(TenantId tenantId, TenantId id, TextPageLink pageLink) { 319 protected List<Edge> findEntities(TenantId tenantId, TenantId id, TextPageLink pageLink) {
147 - return edgeDao.findByTenantIdAndPageLink(id.getId(), pageLink); 320 + return edgeDao.findEdgesByTenantId(id.getId(), pageLink);
148 } 321 }
149 322
150 @Override 323 @Override
151 protected void removeEntity(TenantId tenantId, Edge entity) { 324 protected void removeEntity(TenantId tenantId, Edge entity) {
152 - deleteEdge(tenantId, new EdgeId(entity.getId().getId())); 325 + deleteEdge(tenantId, new EdgeId(entity.getUuidId()));
153 } 326 }
154 }; 327 };
155 328
  329 + private PaginatedRemover<CustomerId, Edge> customerEdgeUnasigner = new PaginatedRemover<CustomerId, Edge>() {
  330 +
  331 + @Override
  332 + protected List<Edge> findEntities(TenantId tenantId, CustomerId id, TextPageLink pageLink) {
  333 + return edgeDao.findEdgesByTenantIdAndCustomerId(tenantId.getId(), id.getId(), pageLink);
  334 + }
  335 +
  336 + @Override
  337 + protected void removeEntity(TenantId tenantId, Edge entity) {
  338 + unassignEdgeFromCustomer(tenantId, new EdgeId(entity.getUuidId()));
  339 + }
  340 + };
  341 +
156 } 342 }
@@ -15,29 +15,21 @@ @@ -15,29 +15,21 @@
15 */ 15 */
16 package org.thingsboard.server.dao.edge; 16 package org.thingsboard.server.dao.edge;
17 17
18 -import com.datastax.driver.core.querybuilder.Select;  
19 import com.google.common.util.concurrent.ListenableFuture; 18 import com.google.common.util.concurrent.ListenableFuture;
20 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
21 import org.springframework.stereotype.Component; 20 import org.springframework.stereotype.Component;
  21 +import org.thingsboard.server.common.data.EntitySubtype;
22 import org.thingsboard.server.common.data.edge.Edge; 22 import org.thingsboard.server.common.data.edge.Edge;
23 -import org.thingsboard.server.common.data.id.TenantId;  
24 import org.thingsboard.server.common.data.page.TextPageLink; 23 import org.thingsboard.server.common.data.page.TextPageLink;
25 -import org.thingsboard.server.dao.DaoUtil;  
26 import org.thingsboard.server.dao.model.nosql.EdgeEntity; 24 import org.thingsboard.server.dao.model.nosql.EdgeEntity;
27 import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao; 25 import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao;
28 import org.thingsboard.server.dao.util.NoSqlDao; 26 import org.thingsboard.server.dao.util.NoSqlDao;
29 27
30 -import java.util.Collections;  
31 import java.util.List; 28 import java.util.List;
  29 +import java.util.Optional;
32 import java.util.UUID; 30 import java.util.UUID;
33 31
34 -import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;  
35 -import static com.datastax.driver.core.querybuilder.QueryBuilder.in;  
36 -import static com.datastax.driver.core.querybuilder.QueryBuilder.select;  
37 -import static org.thingsboard.server.dao.model.ModelConstants.EDGE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME;  
38 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_COLUMN_FAMILY_NAME; 32 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_COLUMN_FAMILY_NAME;
39 -import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY;  
40 -import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY;  
41 33
42 @Component 34 @Component
43 @Slf4j 35 @Slf4j
@@ -54,24 +46,44 @@ public class CassandraEdgeDao extends CassandraAbstractSearchTextDao<EdgeEntity, @@ -54,24 +46,44 @@ public class CassandraEdgeDao extends CassandraAbstractSearchTextDao<EdgeEntity,
54 return EDGE_COLUMN_FAMILY_NAME; 46 return EDGE_COLUMN_FAMILY_NAME;
55 } 47 }
56 48
  49 +
57 @Override 50 @Override
58 - public List<Edge> findByTenantIdAndPageLink(UUID tenantId, TextPageLink pageLink) {  
59 - log.debug("Try to find edges by tenantId [{}] and pageLink [{}]", tenantId, pageLink);  
60 - List<EdgeEntity> edgeEntities = findPageWithTextSearch(new TenantId(tenantId), EDGE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,  
61 - Collections.singletonList(eq(EDGE_TENANT_ID_PROPERTY, tenantId)), pageLink); 51 + public List<Edge> findEdgesByTenantId(UUID tenantId, TextPageLink pageLink) {
  52 + return null;
  53 + }
62 54
63 - log.trace("Found edges [{}] by tenantId [{}] and pageLink [{}]", edgeEntities, tenantId, pageLink);  
64 - return DaoUtil.convertDataList(edgeEntities); 55 + @Override
  56 + public List<Edge> findEdgesByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink) {
  57 + return null;
65 } 58 }
66 59
67 @Override 60 @Override
68 public ListenableFuture<List<Edge>> findEdgesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> edgeIds) { 61 public ListenableFuture<List<Edge>> findEdgesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> edgeIds) {
69 - log.debug("Try to find edges by tenantId [{}] and edge Ids [{}]", tenantId, edgeIds);  
70 - Select select = select().from(getColumnFamilyName());  
71 - Select.Where query = select.where();  
72 - query.and(eq(EDGE_TENANT_ID_PROPERTY, tenantId));  
73 - query.and(in(ID_PROPERTY, edgeIds));  
74 - return findListByStatementAsync(new TenantId(tenantId), query); 62 + return null;
  63 + }
  64 +
  65 + @Override
  66 + public List<Edge> findEdgesByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) {
  67 + return null;
  68 + }
  69 +
  70 + @Override
  71 + public List<Edge> findEdgesByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink) {
  72 + return null;
75 } 73 }
76 74
  75 + @Override
  76 + public ListenableFuture<List<Edge>> findEdgesByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> edgeIds) {
  77 + return null;
  78 + }
  79 +
  80 + @Override
  81 + public Optional<Edge> findEdgeByTenantIdAndName(UUID tenantId, String name) {
  82 + return Optional.empty();
  83 + }
  84 +
  85 + @Override
  86 + public ListenableFuture<List<EntitySubtype>> findTenantEdgeTypesAsync(UUID tenantId) {
  87 + return null;
  88 + }
77 } 89 }
@@ -16,11 +16,14 @@ @@ -16,11 +16,14 @@
16 package org.thingsboard.server.dao.edge; 16 package org.thingsboard.server.dao.edge;
17 17
18 import com.google.common.util.concurrent.ListenableFuture; 18 import com.google.common.util.concurrent.ListenableFuture;
  19 +import org.thingsboard.server.common.data.EntitySubtype;
19 import org.thingsboard.server.common.data.edge.Edge; 20 import org.thingsboard.server.common.data.edge.Edge;
  21 +import org.thingsboard.server.common.data.id.TenantId;
20 import org.thingsboard.server.common.data.page.TextPageLink; 22 import org.thingsboard.server.common.data.page.TextPageLink;
21 import org.thingsboard.server.dao.Dao; 23 import org.thingsboard.server.dao.Dao;
22 24
23 import java.util.List; 25 import java.util.List;
  26 +import java.util.Optional;
24 import java.util.UUID; 27 import java.util.UUID;
25 28
26 /** 29 /**
@@ -30,16 +33,34 @@ import java.util.UUID; @@ -30,16 +33,34 @@ import java.util.UUID;
30 public interface EdgeDao extends Dao<Edge> { 33 public interface EdgeDao extends Dao<Edge> {
31 34
32 /** 35 /**
  36 + * Save or update edge object
  37 + *
  38 + * @param edge the edge object
  39 + * @return saved edge object
  40 + */
  41 + Edge save(TenantId tenantId, Edge edge);
  42 +
  43 + /**
33 * Find edges by tenantId and page link. 44 * Find edges by tenantId and page link.
34 * 45 *
35 * @param tenantId the tenantId 46 * @param tenantId the tenantId
36 * @param pageLink the page link 47 * @param pageLink the page link
37 * @return the list of edge objects 48 * @return the list of edge objects
38 */ 49 */
39 - List<Edge> findByTenantIdAndPageLink(UUID tenantId, TextPageLink pageLink); 50 + List<Edge> findEdgesByTenantId(UUID tenantId, TextPageLink pageLink);
  51 +
  52 + /**
  53 + * Find edges 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 edge objects
  59 + */
  60 + List<Edge> findEdgesByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink);
40 61
41 /** 62 /**
42 - * Find edges by tenantId and edge Ids. 63 + * Find edges by tenantId and edges Ids.
43 * 64 *
44 * @param tenantId the tenantId 65 * @param tenantId the tenantId
45 * @param edgeIds the edge Ids 66 * @param edgeIds the edge Ids
@@ -47,5 +68,53 @@ public interface EdgeDao extends Dao<Edge> { @@ -47,5 +68,53 @@ public interface EdgeDao extends Dao<Edge> {
47 */ 68 */
48 ListenableFuture<List<Edge>> findEdgesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> edgeIds); 69 ListenableFuture<List<Edge>> findEdgesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> edgeIds);
49 70
  71 + /**
  72 + * Find edges by tenantId, customerId and page link.
  73 + *
  74 + * @param tenantId the tenantId
  75 + * @param customerId the customerId
  76 + * @param pageLink the page link
  77 + * @return the list of edge objects
  78 + */
  79 + List<Edge> findEdgesByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink);
  80 +
  81 + /**
  82 + * Find edges 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 edge objects
  89 + */
  90 + List<Edge> findEdgesByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink);
  91 +
  92 +
  93 + /**
  94 + * Find edges by tenantId, customerId and edges Ids.
  95 + *
  96 + * @param tenantId the tenantId
  97 + * @param customerId the customerId
  98 + * @param edgeIds the edge Ids
  99 + * @return the list of edge objects
  100 + */
  101 + ListenableFuture<List<Edge>> findEdgesByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> edgeIds);
  102 +
  103 + /**
  104 + * Find edges by tenantId and edge name.
  105 + *
  106 + * @param tenantId the tenantId
  107 + * @param name the edge name
  108 + * @return the optional edge object
  109 + */
  110 + Optional<Edge> findEdgeByTenantIdAndName(UUID tenantId, String name);
  111 +
  112 + /**
  113 + * Find tenants edge types.
  114 + *
  115 + * @return the list of tenant edge type objects
  116 + */
  117 + ListenableFuture<List<EntitySubtype>> findTenantEdgeTypesAsync(UUID tenantId);
  118 +
50 119
51 } 120 }
@@ -354,6 +354,7 @@ public class ModelConstants { @@ -354,6 +354,7 @@ public class ModelConstants {
354 public static final String EDGE_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; 354 public static final String EDGE_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
355 public static final String EDGE_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY; 355 public static final String EDGE_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY;
356 public static final String EDGE_NAME_PROPERTY = "name"; 356 public static final String EDGE_NAME_PROPERTY = "name";
  357 + public static final String EDGE_TYPE_PROPERTY = "type";
357 public static final String EDGE_CONFIGURATION_PROPERTY = "configuration"; 358 public static final String EDGE_CONFIGURATION_PROPERTY = "configuration";
358 public static final String EDGE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY; 359 public static final String EDGE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
359 360
@@ -37,6 +37,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CONFIGURATION @@ -37,6 +37,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CONFIGURATION
37 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CUSTOMER_ID_PROPERTY; 37 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CUSTOMER_ID_PROPERTY;
38 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_NAME_PROPERTY; 38 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_NAME_PROPERTY;
39 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY; 39 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY;
  40 +import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TYPE_PROPERTY;
40 import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY; 41 import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY;
41 import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY; 42 import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY;
42 43
@@ -56,6 +57,9 @@ public class EdgeEntity implements SearchTextEntity<Edge> { @@ -56,6 +57,9 @@ public class EdgeEntity implements SearchTextEntity<Edge> {
56 @Column(name = EDGE_CUSTOMER_ID_PROPERTY) 57 @Column(name = EDGE_CUSTOMER_ID_PROPERTY)
57 private UUID customerId; 58 private UUID customerId;
58 59
  60 + @Column(name = EDGE_TYPE_PROPERTY)
  61 + private String type;
  62 +
59 @Column(name = EDGE_NAME_PROPERTY) 63 @Column(name = EDGE_NAME_PROPERTY)
60 private String name; 64 private String name;
61 65
@@ -79,6 +83,7 @@ public class EdgeEntity implements SearchTextEntity<Edge> { @@ -79,6 +83,7 @@ public class EdgeEntity implements SearchTextEntity<Edge> {
79 if (edge.getTenantId() != null) { 83 if (edge.getTenantId() != null) {
80 this.tenantId = edge.getTenantId().getId(); 84 this.tenantId = edge.getTenantId().getId();
81 } 85 }
  86 + this.type = edge.getType();
82 this.name = edge.getName(); 87 this.name = edge.getName();
83 this.configuration = edge.getConfiguration(); 88 this.configuration = edge.getConfiguration();
84 this.additionalInfo = edge.getAdditionalInfo(); 89 this.additionalInfo = edge.getAdditionalInfo();
@@ -99,6 +104,7 @@ public class EdgeEntity implements SearchTextEntity<Edge> { @@ -99,6 +104,7 @@ public class EdgeEntity implements SearchTextEntity<Edge> {
99 if (customerId != null) { 104 if (customerId != null) {
100 edge.setCustomerId(new CustomerId(customerId)); 105 edge.setCustomerId(new CustomerId(customerId));
101 } 106 }
  107 + edge.setType(type);
102 edge.setName(name); 108 edge.setName(name);
103 edge.setConfiguration(configuration); 109 edge.setConfiguration(configuration);
104 edge.setAdditionalInfo(additionalInfo); 110 edge.setAdditionalInfo(additionalInfo);
@@ -40,6 +40,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.EDGE_COLUMN_FAMILY @@ -40,6 +40,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.EDGE_COLUMN_FAMILY
40 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CUSTOMER_ID_PROPERTY; 40 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CUSTOMER_ID_PROPERTY;
41 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_NAME_PROPERTY; 41 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_NAME_PROPERTY;
42 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY; 42 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY;
  43 +import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TYPE_PROPERTY;
43 import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY; 44 import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY;
44 45
45 @Data 46 @Data
@@ -55,6 +56,9 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity< @@ -55,6 +56,9 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity<
55 @Column(name = EDGE_CUSTOMER_ID_PROPERTY) 56 @Column(name = EDGE_CUSTOMER_ID_PROPERTY)
56 private String customerId; 57 private String customerId;
57 58
  59 + @Column(name = EDGE_TYPE_PROPERTY)
  60 + private String type;
  61 +
58 @Column(name = EDGE_NAME_PROPERTY) 62 @Column(name = EDGE_NAME_PROPERTY)
59 private String name; 63 private String name;
60 64
@@ -80,6 +84,10 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity< @@ -80,6 +84,10 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity<
80 if (edge.getTenantId() != null) { 84 if (edge.getTenantId() != null) {
81 this.tenantId = UUIDConverter.fromTimeUUID(edge.getTenantId().getId()); 85 this.tenantId = UUIDConverter.fromTimeUUID(edge.getTenantId().getId());
82 } 86 }
  87 + if (edge.getCustomerId() != null) {
  88 + this.customerId = UUIDConverter.fromTimeUUID(edge.getCustomerId().getId());
  89 + }
  90 + this.type = edge.getType();
83 this.name = edge.getName(); 91 this.name = edge.getName();
84 this.configuration = edge.getConfiguration(); 92 this.configuration = edge.getConfiguration();
85 this.additionalInfo = edge.getAdditionalInfo(); 93 this.additionalInfo = edge.getAdditionalInfo();
@@ -109,6 +117,7 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity< @@ -109,6 +117,7 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity<
109 if (customerId != null) { 117 if (customerId != null) {
110 edge.setCustomerId(new CustomerId(UUIDConverter.fromString(customerId))); 118 edge.setCustomerId(new CustomerId(UUIDConverter.fromString(customerId)));
111 } 119 }
  120 + edge.setType(type);
112 edge.setName(name); 121 edge.setName(name);
113 edge.setConfiguration(configuration); 122 edge.setConfiguration(configuration);
114 edge.setAdditionalInfo(additionalInfo); 123 edge.setAdditionalInfo(additionalInfo);
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 * you may not use this file except in compliance with 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 6 * You may obtain a copy of the License at
7 * 7 *
8 - * http://www.apache.org/licenses/LICENSE-2.0 8 + * http://www.apache.org/licenses/LICENSE-2.0
9 * 9 *
10 * Unless required by applicable law or agreed to in writing, software 10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, 11 * distributed under the License is distributed on an "AS IS" BASIS,
@@ -27,13 +27,52 @@ import java.util.List; @@ -27,13 +27,52 @@ import java.util.List;
27 @SqlDao 27 @SqlDao
28 public interface EdgeRepository extends CrudRepository<EdgeEntity, String> { 28 public interface EdgeRepository extends CrudRepository<EdgeEntity, String> {
29 29
30 - @Query("SELECT a FROM EdgeEntity a WHERE a.tenantId = :tenantId " +  
31 - "AND LOWER(a.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " +  
32 - "AND a.id > :idOffset ORDER BY a.id")  
33 - List<EdgeEntity> findByTenantIdAndPageLink(@Param("tenantId") String tenantId,  
34 - @Param("textSearch") String textSearch,  
35 - @Param("idOffset") String idOffset,  
36 - Pageable pageable); 30 + @Query("SELECT d FROM EdgeEntity d WHERE d.tenantId = :tenantId " +
  31 + "AND d.customerId = :customerId " +
  32 + "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:searchText, '%')) " +
  33 + "AND d.id > :idOffset ORDER BY d.id")
  34 + List<EdgeEntity> findByTenantIdAndCustomerId(@Param("tenantId") String tenantId,
  35 + @Param("customerId") String customerId,
  36 + @Param("searchText") String searchText,
  37 + @Param("idOffset") String idOffset,
  38 + Pageable pageable);
  39 +
  40 + @Query("SELECT d FROM EdgeEntity d WHERE d.tenantId = :tenantId " +
  41 + "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " +
  42 + "AND d.id > :idOffset ORDER BY d.id")
  43 + List<EdgeEntity> findByTenantId(@Param("tenantId") String tenantId,
  44 + @Param("textSearch") String textSearch,
  45 + @Param("idOffset") String idOffset,
  46 + Pageable pageable);
  47 +
  48 + @Query("SELECT d FROM EdgeEntity d WHERE d.tenantId = :tenantId " +
  49 + "AND d.type = :type " +
  50 + "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " +
  51 + "AND d.id > :idOffset ORDER BY d.id")
  52 + List<EdgeEntity> findByTenantIdAndType(@Param("tenantId") String tenantId,
  53 + @Param("type") String type,
  54 + @Param("textSearch") String textSearch,
  55 + @Param("idOffset") String idOffset,
  56 + Pageable pageable);
  57 +
  58 + @Query("SELECT d FROM EdgeEntity d WHERE d.tenantId = :tenantId " +
  59 + "AND d.customerId = :customerId " +
  60 + "AND d.type = :type " +
  61 + "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " +
  62 + "AND d.id > :idOffset ORDER BY d.id")
  63 + List<EdgeEntity> findByTenantIdAndCustomerIdAndType(@Param("tenantId") String tenantId,
  64 + @Param("customerId") String customerId,
  65 + @Param("type") String type,
  66 + @Param("textSearch") String textSearch,
  67 + @Param("idOffset") String idOffset,
  68 + Pageable pageable);
  69 +
  70 + @Query("SELECT DISTINCT d.type FROM EdgeEntity d WHERE d.tenantId = :tenantId")
  71 + List<String> findTenantEdgeTypes(@Param("tenantId") String tenantId);
  72 +
  73 + EdgeEntity findByTenantIdAndName(String tenantId, String name);
  74 +
  75 + List<EdgeEntity> findEdgesByTenantIdAndCustomerIdAndIdIn(String tenantId, String customerId, List<String> edgeIds);
37 76
38 List<EdgeEntity> findEdgesByTenantIdAndIdIn(String tenantId, List<String> edgeIds); 77 List<EdgeEntity> findEdgesByTenantIdAndIdIn(String tenantId, List<String> edgeIds);
39 78
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 * you may not use this file except in compliance with 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 6 * You may obtain a copy of the License at
7 * 7 *
8 - * http://www.apache.org/licenses/LICENSE-2.0 8 + * http://www.apache.org/licenses/LICENSE-2.0
9 * 9 *
10 * Unless required by applicable law or agreed to in writing, software 10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, 11 * distributed under the License is distributed on an "AS IS" BASIS,
@@ -20,8 +20,11 @@ import org.springframework.beans.factory.annotation.Autowired; @@ -20,8 +20,11 @@ import org.springframework.beans.factory.annotation.Autowired;
20 import org.springframework.data.domain.PageRequest; 20 import org.springframework.data.domain.PageRequest;
21 import org.springframework.data.repository.CrudRepository; 21 import org.springframework.data.repository.CrudRepository;
22 import org.springframework.stereotype.Component; 22 import org.springframework.stereotype.Component;
  23 +import org.thingsboard.server.common.data.EntitySubtype;
  24 +import org.thingsboard.server.common.data.EntityType;
23 import org.thingsboard.server.common.data.UUIDConverter; 25 import org.thingsboard.server.common.data.UUIDConverter;
24 import org.thingsboard.server.common.data.edge.Edge; 26 import org.thingsboard.server.common.data.edge.Edge;
  27 +import org.thingsboard.server.common.data.id.TenantId;
25 import org.thingsboard.server.common.data.page.TextPageLink; 28 import org.thingsboard.server.common.data.page.TextPageLink;
26 import org.thingsboard.server.dao.DaoUtil; 29 import org.thingsboard.server.dao.DaoUtil;
27 import org.thingsboard.server.dao.edge.EdgeDao; 30 import org.thingsboard.server.dao.edge.EdgeDao;
@@ -29,8 +32,11 @@ import org.thingsboard.server.dao.model.sql.EdgeEntity; @@ -29,8 +32,11 @@ import org.thingsboard.server.dao.model.sql.EdgeEntity;
29 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; 32 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
30 import org.thingsboard.server.dao.util.SqlDao; 33 import org.thingsboard.server.dao.util.SqlDao;
31 34
  35 +import java.util.ArrayList;
  36 +import java.util.Collections;
32 import java.util.List; 37 import java.util.List;
33 import java.util.Objects; 38 import java.util.Objects;
  39 +import java.util.Optional;
34 import java.util.UUID; 40 import java.util.UUID;
35 41
36 import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUID; 42 import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUID;
@@ -45,9 +51,19 @@ public class JpaEdgeDao extends JpaAbstractSearchTextDao<EdgeEntity, Edge> imple @@ -45,9 +51,19 @@ public class JpaEdgeDao extends JpaAbstractSearchTextDao<EdgeEntity, Edge> imple
45 private EdgeRepository edgeRepository; 51 private EdgeRepository edgeRepository;
46 52
47 @Override 53 @Override
48 - public List<Edge> findByTenantIdAndPageLink(UUID tenantId, TextPageLink pageLink) {  
49 - return DaoUtil.convertDataList(edgeRepository  
50 - .findByTenantIdAndPageLink( 54 + protected Class<EdgeEntity> getEntityClass() {
  55 + return EdgeEntity.class;
  56 + }
  57 +
  58 + @Override
  59 + protected CrudRepository<EdgeEntity, String> getCrudRepository() {
  60 + return edgeRepository;
  61 + }
  62 +
  63 + @Override
  64 + public List<Edge> findEdgesByTenantId(UUID tenantId, TextPageLink pageLink) {
  65 + return DaoUtil.convertDataList(
  66 + edgeRepository.findByTenantId(
51 fromTimeUUID(tenantId), 67 fromTimeUUID(tenantId),
52 Objects.toString(pageLink.getTextSearch(), ""), 68 Objects.toString(pageLink.getTextSearch(), ""),
53 pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), 69 pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()),
@@ -60,13 +76,65 @@ public class JpaEdgeDao extends JpaAbstractSearchTextDao<EdgeEntity, Edge> imple @@ -60,13 +76,65 @@ public class JpaEdgeDao extends JpaAbstractSearchTextDao<EdgeEntity, Edge> imple
60 } 76 }
61 77
62 @Override 78 @Override
63 - protected Class<EdgeEntity> getEntityClass() {  
64 - return EdgeEntity.class; 79 + public List<Edge> findEdgesByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) {
  80 + return DaoUtil.convertDataList(
  81 + edgeRepository.findByTenantIdAndCustomerId(
  82 + fromTimeUUID(tenantId),
  83 + fromTimeUUID(customerId),
  84 + Objects.toString(pageLink.getTextSearch(), ""),
  85 + pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()),
  86 + new PageRequest(0, pageLink.getLimit())));
65 } 87 }
66 88
67 @Override 89 @Override
68 - protected CrudRepository<EdgeEntity, String> getCrudRepository() {  
69 - return edgeRepository; 90 + public ListenableFuture<List<Edge>> findEdgesByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> edgeIds) {
  91 + return service.submit(() -> DaoUtil.convertDataList(
  92 + edgeRepository.findEdgesByTenantIdAndCustomerIdAndIdIn(fromTimeUUID(tenantId), fromTimeUUID(customerId), fromTimeUUIDs(edgeIds))));
  93 + }
  94 +
  95 + @Override
  96 + public Optional<Edge> findEdgeByTenantIdAndName(UUID tenantId, String name) {
  97 + Edge edge = DaoUtil.getData(edgeRepository.findByTenantIdAndName(fromTimeUUID(tenantId), name));
  98 + return Optional.ofNullable(edge);
  99 + }
  100 +
  101 + @Override
  102 + public List<Edge> findEdgesByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink) {
  103 + return DaoUtil.convertDataList(
  104 + edgeRepository.findByTenantIdAndType(
  105 + fromTimeUUID(tenantId),
  106 + type,
  107 + Objects.toString(pageLink.getTextSearch(), ""),
  108 + pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()),
  109 + new PageRequest(0, pageLink.getLimit())));
  110 + }
  111 +
  112 + @Override
  113 + public List<Edge> findEdgesByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink) {
  114 + return DaoUtil.convertDataList(
  115 + edgeRepository.findByTenantIdAndCustomerIdAndType(
  116 + fromTimeUUID(tenantId),
  117 + fromTimeUUID(customerId),
  118 + type,
  119 + Objects.toString(pageLink.getTextSearch(), ""),
  120 + pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()),
  121 + new PageRequest(0, pageLink.getLimit())));
  122 + }
  123 +
  124 + @Override
  125 + public ListenableFuture<List<EntitySubtype>> findTenantEdgeTypesAsync(UUID tenantId) {
  126 + return service.submit(() -> convertTenantEdgeTypesToDto(tenantId, edgeRepository.findTenantEdgeTypes(fromTimeUUID(tenantId))));
  127 + }
  128 +
  129 + private List<EntitySubtype> convertTenantEdgeTypesToDto(UUID tenantId, List<String> types) {
  130 + List<EntitySubtype> list = Collections.emptyList();
  131 + if (types != null && !types.isEmpty()) {
  132 + list = new ArrayList<>();
  133 + for (String type : types) {
  134 + list.add(new EntitySubtype(new TenantId(tenantId), EntityType.EDGE, type));
  135 + }
  136 + }
  137 + return list;
70 } 138 }
71 139
72 } 140 }
@@ -29,6 +29,7 @@ import org.thingsboard.server.dao.asset.AssetService; @@ -29,6 +29,7 @@ import org.thingsboard.server.dao.asset.AssetService;
29 import org.thingsboard.server.dao.customer.CustomerService; 29 import org.thingsboard.server.dao.customer.CustomerService;
30 import org.thingsboard.server.dao.dashboard.DashboardService; 30 import org.thingsboard.server.dao.dashboard.DashboardService;
31 import org.thingsboard.server.dao.device.DeviceService; 31 import org.thingsboard.server.dao.device.DeviceService;
  32 +import org.thingsboard.server.dao.edge.EdgeService;
32 import org.thingsboard.server.dao.entity.AbstractEntityService; 33 import org.thingsboard.server.dao.entity.AbstractEntityService;
33 import org.thingsboard.server.dao.entityview.EntityViewService; 34 import org.thingsboard.server.dao.entityview.EntityViewService;
34 import org.thingsboard.server.dao.exception.DataValidationException; 35 import org.thingsboard.server.dao.exception.DataValidationException;
@@ -77,6 +78,9 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @@ -77,6 +78,9 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
77 @Autowired 78 @Autowired
78 private RuleChainService ruleChainService; 79 private RuleChainService ruleChainService;
79 80
  81 + @Autowired
  82 + private EdgeService edgeService;
  83 +
80 @Override 84 @Override
81 public Tenant findTenantById(TenantId tenantId) { 85 public Tenant findTenantById(TenantId tenantId) {
82 log.trace("Executing findTenantById [{}]", tenantId); 86 log.trace("Executing findTenantById [{}]", tenantId);
@@ -109,6 +113,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @@ -109,6 +113,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
109 entityViewService.deleteEntityViewsByTenantId(tenantId); 113 entityViewService.deleteEntityViewsByTenantId(tenantId);
110 assetService.deleteAssetsByTenantId(tenantId); 114 assetService.deleteAssetsByTenantId(tenantId);
111 deviceService.deleteDevicesByTenantId(tenantId); 115 deviceService.deleteDevicesByTenantId(tenantId);
  116 + edgeService.deleteEdgesByTenantId(tenantId);
112 userService.deleteTenantAdmins(tenantId); 117 userService.deleteTenantAdmins(tenantId);
113 ruleChainService.deleteRuleChainsByTenantId(tenantId); 118 ruleChainService.deleteRuleChainsByTenantId(tenantId);
114 tenantDao.removeById(tenantId, tenantId.getId()); 119 tenantDao.removeById(tenantId, tenantId.getId());
@@ -254,6 +254,7 @@ CREATE TABLE IF NOT EXISTS edge ( @@ -254,6 +254,7 @@ CREATE TABLE IF NOT EXISTS edge (
254 additional_info varchar, 254 additional_info varchar,
255 customer_id varchar(31), 255 customer_id varchar(31),
256 configuration varchar(10000000), 256 configuration varchar(10000000),
  257 + type varchar(255),
257 name varchar(255), 258 name varchar(255),
258 search_text varchar(255), 259 search_text varchar(255),
259 tenant_id varchar(31) 260 tenant_id varchar(31)
@@ -45,6 +45,7 @@ import org.thingsboard.server.dao.customer.CustomerService; @@ -45,6 +45,7 @@ import org.thingsboard.server.dao.customer.CustomerService;
45 import org.thingsboard.server.dao.dashboard.DashboardService; 45 import org.thingsboard.server.dao.dashboard.DashboardService;
46 import org.thingsboard.server.dao.device.DeviceCredentialsService; 46 import org.thingsboard.server.dao.device.DeviceCredentialsService;
47 import org.thingsboard.server.dao.device.DeviceService; 47 import org.thingsboard.server.dao.device.DeviceService;
  48 +import org.thingsboard.server.dao.edge.EdgeService;
48 import org.thingsboard.server.dao.entityview.EntityViewService; 49 import org.thingsboard.server.dao.entityview.EntityViewService;
49 import org.thingsboard.server.dao.event.EventService; 50 import org.thingsboard.server.dao.event.EventService;
50 import org.thingsboard.server.dao.relation.RelationService; 51 import org.thingsboard.server.dao.relation.RelationService;
@@ -122,6 +123,9 @@ public abstract class AbstractServiceTest { @@ -122,6 +123,9 @@ public abstract class AbstractServiceTest {
122 protected RuleChainService ruleChainService; 123 protected RuleChainService ruleChainService;
123 124
124 @Autowired 125 @Autowired
  126 + protected EdgeService edgeService;
  127 +
  128 + @Autowired
125 private ComponentDescriptorService componentDescriptorService; 129 private ComponentDescriptorService componentDescriptorService;
126 130
127 class IdComparator<D extends BaseData<? extends UUIDBased>> implements Comparator<D> { 131 class IdComparator<D extends BaseData<? extends UUIDBased>> implements Comparator<D> {
  1 +/**
  2 + * Copyright © 2016-2019 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.service;
  17 +
  18 +import com.datastax.driver.core.utils.UUIDs;
  19 +import org.apache.commons.lang3.RandomStringUtils;
  20 +import org.junit.After;
  21 +import org.junit.Assert;
  22 +import org.junit.Before;
  23 +import org.junit.Test;
  24 +import org.thingsboard.server.common.data.Customer;
  25 +import org.thingsboard.server.common.data.EntitySubtype;
  26 +import org.thingsboard.server.common.data.Tenant;
  27 +import org.thingsboard.server.common.data.edge.Edge;
  28 +import org.thingsboard.server.common.data.id.CustomerId;
  29 +import org.thingsboard.server.common.data.id.TenantId;
  30 +import org.thingsboard.server.common.data.page.TextPageData;
  31 +import org.thingsboard.server.common.data.page.TextPageLink;
  32 +import org.thingsboard.server.dao.exception.DataValidationException;
  33 +
  34 +import java.util.ArrayList;
  35 +import java.util.Collections;
  36 +import java.util.List;
  37 +
  38 +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
  39 +
  40 +public abstract class BaseEdgeServiceTest extends AbstractServiceTest {
  41 +
  42 + private IdComparator<Edge> idComparator = new IdComparator<>();
  43 +
  44 + private TenantId tenantId;
  45 +
  46 + @Before
  47 + public void before() {
  48 + Tenant tenant = new Tenant();
  49 + tenant.setTitle("My tenant");
  50 + Tenant savedTenant = tenantService.saveTenant(tenant);
  51 + Assert.assertNotNull(savedTenant);
  52 + tenantId = savedTenant.getId();
  53 + }
  54 +
  55 + @After
  56 + public void after() {
  57 + tenantService.deleteTenant(tenantId);
  58 + }
  59 +
  60 + @Test
  61 + public void testSaveEdge() {
  62 + Edge edge = new Edge();
  63 + edge.setTenantId(tenantId);
  64 + edge.setName("My edge");
  65 + edge.setType("default");
  66 + Edge savedEdge = edgeService.saveEdge(edge);
  67 +
  68 + Assert.assertNotNull(savedEdge);
  69 + Assert.assertNotNull(savedEdge.getId());
  70 + Assert.assertTrue(savedEdge.getCreatedTime() > 0);
  71 + Assert.assertEquals(edge.getTenantId(), savedEdge.getTenantId());
  72 + Assert.assertNotNull(savedEdge.getCustomerId());
  73 + Assert.assertEquals(NULL_UUID, savedEdge.getCustomerId().getId());
  74 + Assert.assertEquals(edge.getName(), savedEdge.getName());
  75 +
  76 + savedEdge.setName("My new edge");
  77 +
  78 + edgeService.saveEdge(savedEdge);
  79 + Edge foundEdge = edgeService.findEdgeById(tenantId, savedEdge.getId());
  80 + Assert.assertEquals(foundEdge.getName(), savedEdge.getName());
  81 +
  82 + edgeService.deleteEdge(tenantId, savedEdge.getId());
  83 + }
  84 +
  85 + @Test(expected = DataValidationException.class)
  86 + public void testSaveEdgeWithEmptyName() {
  87 + Edge edge = new Edge();
  88 + edge.setType("default");
  89 + edge.setTenantId(tenantId);
  90 + edgeService.saveEdge(edge);
  91 + }
  92 +
  93 + @Test(expected = DataValidationException.class)
  94 + public void testSaveEdgeWithEmptyTenant() {
  95 + Edge edge = new Edge();
  96 + edge.setName("My edge");
  97 + edge.setType("default");
  98 + edgeService.saveEdge(edge);
  99 + }
  100 +
  101 + @Test(expected = DataValidationException.class)
  102 + public void testSaveEdgeWithInvalidTenant() {
  103 + Edge edge = new Edge();
  104 + edge.setName("My edge");
  105 + edge.setType("default");
  106 + edge.setTenantId(new TenantId(UUIDs.timeBased()));
  107 + edgeService.saveEdge(edge);
  108 + }
  109 +
  110 + @Test(expected = DataValidationException.class)
  111 + public void testAssignEdgeToNonExistentCustomer() {
  112 + Edge edge = new Edge();
  113 + edge.setName("My edge");
  114 + edge.setType("default");
  115 + edge.setTenantId(tenantId);
  116 + edge = edgeService.saveEdge(edge);
  117 + try {
  118 + edgeService.assignEdgeToCustomer(tenantId, edge.getId(), new CustomerId(UUIDs.timeBased()));
  119 + } finally {
  120 + edgeService.deleteEdge(tenantId, edge.getId());
  121 + }
  122 + }
  123 +
  124 + @Test(expected = DataValidationException.class)
  125 + public void testAssignEdgeToCustomerFromDifferentTenant() {
  126 + Edge edge = new Edge();
  127 + edge.setName("My edge");
  128 + edge.setType("default");
  129 + edge.setTenantId(tenantId);
  130 + edge = edgeService.saveEdge(edge);
  131 + Tenant tenant = new Tenant();
  132 + tenant.setTitle("Test different tenant");
  133 + tenant = tenantService.saveTenant(tenant);
  134 + Customer customer = new Customer();
  135 + customer.setTenantId(tenant.getId());
  136 + customer.setTitle("Test different customer");
  137 + customer = customerService.saveCustomer(customer);
  138 + try {
  139 + edgeService.assignEdgeToCustomer(tenantId, edge.getId(), customer.getId());
  140 + } finally {
  141 + edgeService.deleteEdge(tenantId, edge.getId());
  142 + tenantService.deleteTenant(tenant.getId());
  143 + }
  144 + }
  145 +
  146 + @Test
  147 + public void testFindEdgeById() {
  148 + Edge edge = new Edge();
  149 + edge.setTenantId(tenantId);
  150 + edge.setName("My edge");
  151 + edge.setType("default");
  152 + Edge savedEdge = edgeService.saveEdge(edge);
  153 + Edge foundEdge = edgeService.findEdgeById(tenantId, savedEdge.getId());
  154 + Assert.assertNotNull(foundEdge);
  155 + Assert.assertEquals(savedEdge, foundEdge);
  156 + edgeService.deleteEdge(tenantId, savedEdge.getId());
  157 + }
  158 +
  159 + @Test
  160 + public void testFindEdgeTypesByTenantId() throws Exception {
  161 + List<Edge> edges = new ArrayList<>();
  162 + try {
  163 + for (int i = 0; i < 3; i++) {
  164 + Edge edge = new Edge();
  165 + edge.setTenantId(tenantId);
  166 + edge.setName("My edge B" + i);
  167 + edge.setType("typeB");
  168 + edges.add(edgeService.saveEdge(edge));
  169 + }
  170 + for (int i = 0; i < 7; i++) {
  171 + Edge edge = new Edge();
  172 + edge.setTenantId(tenantId);
  173 + edge.setName("My edge C" + i);
  174 + edge.setType("typeC");
  175 + edges.add(edgeService.saveEdge(edge));
  176 + }
  177 + for (int i = 0; i < 9; i++) {
  178 + Edge edge = new Edge();
  179 + edge.setTenantId(tenantId);
  180 + edge.setName("My edge A" + i);
  181 + edge.setType("typeA");
  182 + edges.add(edgeService.saveEdge(edge));
  183 + }
  184 + List<EntitySubtype> edgeTypes = edgeService.findEdgeTypesByTenantId(tenantId).get();
  185 + Assert.assertNotNull(edgeTypes);
  186 + Assert.assertEquals(3, edgeTypes.size());
  187 + Assert.assertEquals("typeA", edgeTypes.get(0).getType());
  188 + Assert.assertEquals("typeB", edgeTypes.get(1).getType());
  189 + Assert.assertEquals("typeC", edgeTypes.get(2).getType());
  190 + } finally {
  191 + edges.forEach((edge) -> {
  192 + edgeService.deleteEdge(tenantId, edge.getId());
  193 + });
  194 + }
  195 + }
  196 +
  197 + @Test
  198 + public void testDeleteEdge() {
  199 + Edge edge = new Edge();
  200 + edge.setTenantId(tenantId);
  201 + edge.setName("My edge");
  202 + edge.setType("default");
  203 + Edge savedEdge = edgeService.saveEdge(edge);
  204 + Edge foundEdge = edgeService.findEdgeById(tenantId, savedEdge.getId());
  205 + Assert.assertNotNull(foundEdge);
  206 + edgeService.deleteEdge(tenantId, savedEdge.getId());
  207 + foundEdge = edgeService.findEdgeById(tenantId, savedEdge.getId());
  208 + Assert.assertNull(foundEdge);
  209 + }
  210 +
  211 + @Test
  212 + public void testFindEdgesByTenantId() {
  213 + Tenant tenant = new Tenant();
  214 + tenant.setTitle("Test tenant");
  215 + tenant = tenantService.saveTenant(tenant);
  216 +
  217 + TenantId tenantId = tenant.getId();
  218 +
  219 + List<Edge> edges = new ArrayList<>();
  220 + for (int i = 0; i < 178; i++) {
  221 + Edge edge = new Edge();
  222 + edge.setTenantId(tenantId);
  223 + edge.setName("Edge" + i);
  224 + edge.setType("default");
  225 + edges.add(edgeService.saveEdge(edge));
  226 + }
  227 +
  228 + List<Edge> loadedEdges = new ArrayList<>();
  229 + TextPageLink pageLink = new TextPageLink(23);
  230 + TextPageData<Edge> pageData = null;
  231 + do {
  232 + pageData = edgeService.findEdgesByTenantId(tenantId, pageLink);
  233 + loadedEdges.addAll(pageData.getData());
  234 + if (pageData.hasNext()) {
  235 + pageLink = pageData.getNextPageLink();
  236 + }
  237 + } while (pageData.hasNext());
  238 +
  239 + Collections.sort(edges, idComparator);
  240 + Collections.sort(loadedEdges, idComparator);
  241 +
  242 + Assert.assertEquals(edges, loadedEdges);
  243 +
  244 + edgeService.deleteEdgesByTenantId(tenantId);
  245 +
  246 + pageLink = new TextPageLink(33);
  247 + pageData = edgeService.findEdgesByTenantId(tenantId, pageLink);
  248 + Assert.assertFalse(pageData.hasNext());
  249 + Assert.assertTrue(pageData.getData().isEmpty());
  250 +
  251 + tenantService.deleteTenant(tenantId);
  252 + }
  253 +
  254 + @Test
  255 + public void testFindEdgesByTenantIdAndName() {
  256 + String title1 = "Edge title 1";
  257 + List<Edge> edgesTitle1 = new ArrayList<>();
  258 + for (int i = 0; i < 143; i++) {
  259 + Edge edge = new Edge();
  260 + edge.setTenantId(tenantId);
  261 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  262 + String name = title1 + suffix;
  263 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  264 + edge.setName(name);
  265 + edge.setType("default");
  266 + edgesTitle1.add(edgeService.saveEdge(edge));
  267 + }
  268 + String title2 = "Edge title 2";
  269 + List<Edge> edgesTitle2 = new ArrayList<>();
  270 + for (int i = 0; i < 175; i++) {
  271 + Edge edge = new Edge();
  272 + edge.setTenantId(tenantId);
  273 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  274 + String name = title2 + suffix;
  275 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  276 + edge.setName(name);
  277 + edge.setType("default");
  278 + edgesTitle2.add(edgeService.saveEdge(edge));
  279 + }
  280 +
  281 + List<Edge> loadedEdgesTitle1 = new ArrayList<>();
  282 + TextPageLink pageLink = new TextPageLink(15, title1);
  283 + TextPageData<Edge> pageData = null;
  284 + do {
  285 + pageData = edgeService.findEdgesByTenantId(tenantId, pageLink);
  286 + loadedEdgesTitle1.addAll(pageData.getData());
  287 + if (pageData.hasNext()) {
  288 + pageLink = pageData.getNextPageLink();
  289 + }
  290 + } while (pageData.hasNext());
  291 +
  292 + Collections.sort(edgesTitle1, idComparator);
  293 + Collections.sort(loadedEdgesTitle1, idComparator);
  294 +
  295 + Assert.assertEquals(edgesTitle1, loadedEdgesTitle1);
  296 +
  297 + List<Edge> loadedEdgesTitle2 = new ArrayList<>();
  298 + pageLink = new TextPageLink(4, title2);
  299 + do {
  300 + pageData = edgeService.findEdgesByTenantId(tenantId, pageLink);
  301 + loadedEdgesTitle2.addAll(pageData.getData());
  302 + if (pageData.hasNext()) {
  303 + pageLink = pageData.getNextPageLink();
  304 + }
  305 + } while (pageData.hasNext());
  306 +
  307 + Collections.sort(edgesTitle2, idComparator);
  308 + Collections.sort(loadedEdgesTitle2, idComparator);
  309 +
  310 + Assert.assertEquals(edgesTitle2, loadedEdgesTitle2);
  311 +
  312 + for (Edge edge : loadedEdgesTitle1) {
  313 + edgeService.deleteEdge(tenantId, edge.getId());
  314 + }
  315 +
  316 + pageLink = new TextPageLink(4, title1);
  317 + pageData = edgeService.findEdgesByTenantId(tenantId, pageLink);
  318 + Assert.assertFalse(pageData.hasNext());
  319 + Assert.assertEquals(0, pageData.getData().size());
  320 +
  321 + for (Edge edge : loadedEdgesTitle2) {
  322 + edgeService.deleteEdge(tenantId, edge.getId());
  323 + }
  324 +
  325 + pageLink = new TextPageLink(4, title2);
  326 + pageData = edgeService.findEdgesByTenantId(tenantId, pageLink);
  327 + Assert.assertFalse(pageData.hasNext());
  328 + Assert.assertEquals(0, pageData.getData().size());
  329 + }
  330 +
  331 + @Test
  332 + public void testFindEdgesByTenantIdAndType() {
  333 + String title1 = "Edge title 1";
  334 + String type1 = "typeA";
  335 + List<Edge> edgesType1 = new ArrayList<>();
  336 + for (int i = 0; i < 143; i++) {
  337 + Edge edge = new Edge();
  338 + edge.setTenantId(tenantId);
  339 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  340 + String name = title1 + suffix;
  341 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  342 + edge.setName(name);
  343 + edge.setType(type1);
  344 + edgesType1.add(edgeService.saveEdge(edge));
  345 + }
  346 + String title2 = "Edge title 2";
  347 + String type2 = "typeB";
  348 + List<Edge> edgesType2 = new ArrayList<>();
  349 + for (int i = 0; i < 175; i++) {
  350 + Edge edge = new Edge();
  351 + edge.setTenantId(tenantId);
  352 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  353 + String name = title2 + suffix;
  354 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  355 + edge.setName(name);
  356 + edge.setType(type2);
  357 + edgesType2.add(edgeService.saveEdge(edge));
  358 + }
  359 +
  360 + List<Edge> loadedEdgesType1 = new ArrayList<>();
  361 + TextPageLink pageLink = new TextPageLink(15);
  362 + TextPageData<Edge> pageData = null;
  363 + do {
  364 + pageData = edgeService.findEdgesByTenantIdAndType(tenantId, type1, pageLink);
  365 + loadedEdgesType1.addAll(pageData.getData());
  366 + if (pageData.hasNext()) {
  367 + pageLink = pageData.getNextPageLink();
  368 + }
  369 + } while (pageData.hasNext());
  370 +
  371 + Collections.sort(edgesType1, idComparator);
  372 + Collections.sort(loadedEdgesType1, idComparator);
  373 +
  374 + Assert.assertEquals(edgesType1, loadedEdgesType1);
  375 +
  376 + List<Edge> loadedEdgesType2 = new ArrayList<>();
  377 + pageLink = new TextPageLink(4);
  378 + do {
  379 + pageData = edgeService.findEdgesByTenantIdAndType(tenantId, type2, pageLink);
  380 + loadedEdgesType2.addAll(pageData.getData());
  381 + if (pageData.hasNext()) {
  382 + pageLink = pageData.getNextPageLink();
  383 + }
  384 + } while (pageData.hasNext());
  385 +
  386 + Collections.sort(edgesType2, idComparator);
  387 + Collections.sort(loadedEdgesType2, idComparator);
  388 +
  389 + Assert.assertEquals(edgesType2, loadedEdgesType2);
  390 +
  391 + for (Edge edge : loadedEdgesType1) {
  392 + edgeService.deleteEdge(tenantId, edge.getId());
  393 + }
  394 +
  395 + pageLink = new TextPageLink(4);
  396 + pageData = edgeService.findEdgesByTenantIdAndType(tenantId, type1, pageLink);
  397 + Assert.assertFalse(pageData.hasNext());
  398 + Assert.assertEquals(0, pageData.getData().size());
  399 +
  400 + for (Edge edge : loadedEdgesType2) {
  401 + edgeService.deleteEdge(tenantId, edge.getId());
  402 + }
  403 +
  404 + pageLink = new TextPageLink(4);
  405 + pageData = edgeService.findEdgesByTenantIdAndType(tenantId, type2, pageLink);
  406 + Assert.assertFalse(pageData.hasNext());
  407 + Assert.assertEquals(0, pageData.getData().size());
  408 + }
  409 +
  410 + @Test
  411 + public void testFindEdgesByTenantIdAndCustomerId() {
  412 + Tenant tenant = new Tenant();
  413 + tenant.setTitle("Test tenant");
  414 + tenant = tenantService.saveTenant(tenant);
  415 +
  416 + TenantId tenantId = tenant.getId();
  417 +
  418 + Customer customer = new Customer();
  419 + customer.setTitle("Test customer");
  420 + customer.setTenantId(tenantId);
  421 + customer = customerService.saveCustomer(customer);
  422 + CustomerId customerId = customer.getId();
  423 +
  424 + List<Edge> edges = new ArrayList<>();
  425 + for (int i = 0; i < 278; i++) {
  426 + Edge edge = new Edge();
  427 + edge.setTenantId(tenantId);
  428 + edge.setName("Edge" + i);
  429 + edge.setType("default");
  430 + edge = edgeService.saveEdge(edge);
  431 + edges.add(edgeService.assignEdgeToCustomer(tenantId, edge.getId(), customerId));
  432 + }
  433 +
  434 + List<Edge> loadedEdges = new ArrayList<>();
  435 + TextPageLink pageLink = new TextPageLink(23);
  436 + TextPageData<Edge> pageData = null;
  437 + do {
  438 + pageData = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink);
  439 + loadedEdges.addAll(pageData.getData());
  440 + if (pageData.hasNext()) {
  441 + pageLink = pageData.getNextPageLink();
  442 + }
  443 + } while (pageData.hasNext());
  444 +
  445 + Collections.sort(edges, idComparator);
  446 + Collections.sort(loadedEdges, idComparator);
  447 +
  448 + Assert.assertEquals(edges, loadedEdges);
  449 +
  450 + edgeService.unassignCustomerEdges(tenantId, customerId);
  451 +
  452 + pageLink = new TextPageLink(33);
  453 + pageData = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink);
  454 + Assert.assertFalse(pageData.hasNext());
  455 + Assert.assertTrue(pageData.getData().isEmpty());
  456 +
  457 + tenantService.deleteTenant(tenantId);
  458 + }
  459 +
  460 + @Test
  461 + public void testFindEdgesByTenantIdCustomerIdAndName() {
  462 +
  463 + Customer customer = new Customer();
  464 + customer.setTitle("Test customer");
  465 + customer.setTenantId(tenantId);
  466 + customer = customerService.saveCustomer(customer);
  467 + CustomerId customerId = customer.getId();
  468 +
  469 + String title1 = "Edge title 1";
  470 + List<Edge> edgesTitle1 = new ArrayList<>();
  471 + for (int i = 0; i < 175; i++) {
  472 + Edge edge = new Edge();
  473 + edge.setTenantId(tenantId);
  474 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  475 + String name = title1 + suffix;
  476 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  477 + edge.setName(name);
  478 + edge.setType("default");
  479 + edge = edgeService.saveEdge(edge);
  480 + edgesTitle1.add(edgeService.assignEdgeToCustomer(tenantId, edge.getId(), customerId));
  481 + }
  482 + String title2 = "Edge title 2";
  483 + List<Edge> edgesTitle2 = new ArrayList<>();
  484 + for (int i = 0; i < 143; i++) {
  485 + Edge edge = new Edge();
  486 + edge.setTenantId(tenantId);
  487 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  488 + String name = title2 + suffix;
  489 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  490 + edge.setName(name);
  491 + edge.setType("default");
  492 + edge = edgeService.saveEdge(edge);
  493 + edgesTitle2.add(edgeService.assignEdgeToCustomer(tenantId, edge.getId(), customerId));
  494 + }
  495 +
  496 + List<Edge> loadedEdgesTitle1 = new ArrayList<>();
  497 + TextPageLink pageLink = new TextPageLink(15, title1);
  498 + TextPageData<Edge> pageData = null;
  499 + do {
  500 + pageData = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink);
  501 + loadedEdgesTitle1.addAll(pageData.getData());
  502 + if (pageData.hasNext()) {
  503 + pageLink = pageData.getNextPageLink();
  504 + }
  505 + } while (pageData.hasNext());
  506 +
  507 + Collections.sort(edgesTitle1, idComparator);
  508 + Collections.sort(loadedEdgesTitle1, idComparator);
  509 +
  510 + Assert.assertEquals(edgesTitle1, loadedEdgesTitle1);
  511 +
  512 + List<Edge> loadedEdgesTitle2 = new ArrayList<>();
  513 + pageLink = new TextPageLink(4, title2);
  514 + do {
  515 + pageData = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink);
  516 + loadedEdgesTitle2.addAll(pageData.getData());
  517 + if (pageData.hasNext()) {
  518 + pageLink = pageData.getNextPageLink();
  519 + }
  520 + } while (pageData.hasNext());
  521 +
  522 + Collections.sort(edgesTitle2, idComparator);
  523 + Collections.sort(loadedEdgesTitle2, idComparator);
  524 +
  525 + Assert.assertEquals(edgesTitle2, loadedEdgesTitle2);
  526 +
  527 + for (Edge edge : loadedEdgesTitle1) {
  528 + edgeService.deleteEdge(tenantId, edge.getId());
  529 + }
  530 +
  531 + pageLink = new TextPageLink(4, title1);
  532 + pageData = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink);
  533 + Assert.assertFalse(pageData.hasNext());
  534 + Assert.assertEquals(0, pageData.getData().size());
  535 +
  536 + for (Edge edge : loadedEdgesTitle2) {
  537 + edgeService.deleteEdge(tenantId, edge.getId());
  538 + }
  539 +
  540 + pageLink = new TextPageLink(4, title2);
  541 + pageData = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink);
  542 + Assert.assertFalse(pageData.hasNext());
  543 + Assert.assertEquals(0, pageData.getData().size());
  544 + customerService.deleteCustomer(tenantId, customerId);
  545 + }
  546 +
  547 + @Test
  548 + public void testFindEdgesByTenantIdCustomerIdAndType() {
  549 +
  550 + Customer customer = new Customer();
  551 + customer.setTitle("Test customer");
  552 + customer.setTenantId(tenantId);
  553 + customer = customerService.saveCustomer(customer);
  554 + CustomerId customerId = customer.getId();
  555 +
  556 + String title1 = "Edge title 1";
  557 + String type1 = "typeC";
  558 + List<Edge> edgesType1 = new ArrayList<>();
  559 + for (int i = 0; i < 175; i++) {
  560 + Edge edge = new Edge();
  561 + edge.setTenantId(tenantId);
  562 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  563 + String name = title1 + suffix;
  564 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  565 + edge.setName(name);
  566 + edge.setType(type1);
  567 + edge = edgeService.saveEdge(edge);
  568 + edgesType1.add(edgeService.assignEdgeToCustomer(tenantId, edge.getId(), customerId));
  569 + }
  570 + String title2 = "Edge title 2";
  571 + String type2 = "typeD";
  572 + List<Edge> edgesType2 = new ArrayList<>();
  573 + for (int i = 0; i < 143; i++) {
  574 + Edge edge = new Edge();
  575 + edge.setTenantId(tenantId);
  576 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  577 + String name = title2 + suffix;
  578 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  579 + edge.setName(name);
  580 + edge.setType(type2);
  581 + edge = edgeService.saveEdge(edge);
  582 + edgesType2.add(edgeService.assignEdgeToCustomer(tenantId, edge.getId(), customerId));
  583 + }
  584 +
  585 + List<Edge> loadedEdgesType1 = new ArrayList<>();
  586 + TextPageLink pageLink = new TextPageLink(15);
  587 + TextPageData<Edge> pageData = null;
  588 + do {
  589 + pageData = edgeService.findEdgesByTenantIdAndCustomerIdAndType(tenantId, customerId, type1, pageLink);
  590 + loadedEdgesType1.addAll(pageData.getData());
  591 + if (pageData.hasNext()) {
  592 + pageLink = pageData.getNextPageLink();
  593 + }
  594 + } while (pageData.hasNext());
  595 +
  596 + Collections.sort(edgesType1, idComparator);
  597 + Collections.sort(loadedEdgesType1, idComparator);
  598 +
  599 + Assert.assertEquals(edgesType1, loadedEdgesType1);
  600 +
  601 + List<Edge> loadedEdgesType2 = new ArrayList<>();
  602 + pageLink = new TextPageLink(4);
  603 + do {
  604 + pageData = edgeService.findEdgesByTenantIdAndCustomerIdAndType(tenantId, customerId, type2, pageLink);
  605 + loadedEdgesType2.addAll(pageData.getData());
  606 + if (pageData.hasNext()) {
  607 + pageLink = pageData.getNextPageLink();
  608 + }
  609 + } while (pageData.hasNext());
  610 +
  611 + Collections.sort(edgesType2, idComparator);
  612 + Collections.sort(loadedEdgesType2, idComparator);
  613 +
  614 + Assert.assertEquals(edgesType2, loadedEdgesType2);
  615 +
  616 + for (Edge edge : loadedEdgesType1) {
  617 + edgeService.deleteEdge(tenantId, edge.getId());
  618 + }
  619 +
  620 + pageLink = new TextPageLink(4);
  621 + pageData = edgeService.findEdgesByTenantIdAndCustomerIdAndType(tenantId, customerId, type1, pageLink);
  622 + Assert.assertFalse(pageData.hasNext());
  623 + Assert.assertEquals(0, pageData.getData().size());
  624 +
  625 + for (Edge edge : loadedEdgesType2) {
  626 + edgeService.deleteEdge(tenantId, edge.getId());
  627 + }
  628 +
  629 + pageLink = new TextPageLink(4);
  630 + pageData = edgeService.findEdgesByTenantIdAndCustomerIdAndType(tenantId, customerId, type2, pageLink);
  631 + Assert.assertFalse(pageData.hasNext());
  632 + Assert.assertEquals(0, pageData.getData().size());
  633 + customerService.deleteCustomer(tenantId, customerId);
  634 + }
  635 +
  636 +}
  1 +/**
  2 + * Copyright © 2016-2019 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.service.nosql;
  17 +
  18 +import org.thingsboard.server.dao.service.BaseEdgeServiceTest;
  19 +import org.thingsboard.server.dao.service.DaoNoSqlTest;
  20 +
  21 +@DaoNoSqlTest
  22 +public class EdgeServiceNoSqlTest extends BaseEdgeServiceTest {
  23 +}
  1 +/**
  2 + * Copyright © 2016-2019 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.service.sql;
  17 +
  18 +import org.thingsboard.server.dao.service.BaseEdgeServiceTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
  20 +
  21 +@DaoSqlTest
  22 +public class EdgeServiceSqlTest extends BaseEdgeServiceTest {
  23 +}
@@ -30,6 +30,9 @@ caffeine.specs.entityViews.maxSize=100000 @@ -30,6 +30,9 @@ caffeine.specs.entityViews.maxSize=100000
30 caffeine.specs.claimDevices.timeToLiveInMinutes=1440 30 caffeine.specs.claimDevices.timeToLiveInMinutes=1440
31 caffeine.specs.claimDevices.maxSize=100000 31 caffeine.specs.claimDevices.maxSize=100000
32 32
  33 +caffeine.specs.edges.timeToLiveInMinutes=1440
  34 +caffeine.specs.edges.maxSize=100000
  35 +
33 redis.connection.host=localhost 36 redis.connection.host=localhost
34 redis.connection.port=6379 37 redis.connection.port=6379
35 redis.connection.db=0 38 redis.connection.db=0