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 15 */
16 16 package org.thingsboard.server.controller;
17 17
  18 +import com.google.common.util.concurrent.ListenableFuture;
18 19 import org.springframework.http.HttpStatus;
19 20 import org.springframework.security.access.prepost.PreAuthorize;
20 21 import org.springframework.web.bind.annotation.PathVariable;
... ... @@ -25,14 +26,22 @@ import org.springframework.web.bind.annotation.RequestParam;
25 26 import org.springframework.web.bind.annotation.ResponseBody;
26 27 import org.springframework.web.bind.annotation.ResponseStatus;
27 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 32 import org.thingsboard.server.common.data.EntityType;
29 33 import org.thingsboard.server.common.data.audit.ActionType;
  34 +import org.thingsboard.server.common.data.device.DeviceSearchQuery;
30 35 import org.thingsboard.server.common.data.edge.Edge;
  36 +import org.thingsboard.server.common.data.edge.EdgeSearchQuery;
31 37 import org.thingsboard.server.common.data.exception.ThingsboardException;
  38 +import org.thingsboard.server.common.data.id.CustomerId;
32 39 import org.thingsboard.server.common.data.id.EdgeId;
33 40 import org.thingsboard.server.common.data.id.TenantId;
34 41 import org.thingsboard.server.common.data.page.TextPageData;
35 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 45 import org.thingsboard.server.service.security.model.SecurityUser;
37 46 import org.thingsboard.server.service.security.permission.Operation;
38 47 import org.thingsboard.server.service.security.permission.Resource;
... ... @@ -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 96 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
107 97 @RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.DELETE)
108 98 @ResponseStatus(value = HttpStatus.OK)
... ... @@ -129,35 +119,209 @@ public class EdgeController extends BaseController {
129 119 }
130 120
131 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 264 @RequestMapping(value = "/edges", params = {"edgeIds"}, method = RequestMethod.GET)
133 265 @ResponseBody
134 266 public List<Edge> getEdgesByIds(
135 267 @RequestParam("edgeIds") String[] strEdgeIds) throws ThingsboardException {
136 268 checkArrayParameter("edgeIds", strEdgeIds);
137 269 try {
138   - accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, Operation.READ);
139 270 SecurityUser user = getCurrentUser();
140 271 TenantId tenantId = user.getTenantId();
  272 + CustomerId customerId = user.getCustomerId();
141 273 List<EdgeId> edgeIds = new ArrayList<>();
142 274 for (String strEdgeId : strEdgeIds) {
143 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 284 } catch (Exception e) {
148 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 29 import org.thingsboard.server.common.data.EntityView;
30 30 import org.thingsboard.server.common.data.Tenant;
31 31 import org.thingsboard.server.common.data.asset.Asset;
  32 +import org.thingsboard.server.common.data.edge.Edge;
32 33 import org.thingsboard.server.common.data.exception.ThingsboardException;
33 34 import org.thingsboard.server.common.data.id.AssetId;
34 35 import org.thingsboard.server.common.data.id.CustomerId;
35 36 import org.thingsboard.server.common.data.id.DeviceId;
  37 +import org.thingsboard.server.common.data.id.EdgeId;
36 38 import org.thingsboard.server.common.data.id.EntityId;
37 39 import org.thingsboard.server.common.data.id.EntityIdFactory;
38 40 import org.thingsboard.server.common.data.id.EntityViewId;
... ... @@ -46,6 +48,7 @@ import org.thingsboard.server.dao.alarm.AlarmService;
46 48 import org.thingsboard.server.dao.asset.AssetService;
47 49 import org.thingsboard.server.dao.customer.CustomerService;
48 50 import org.thingsboard.server.dao.device.DeviceService;
  51 +import org.thingsboard.server.dao.edge.EdgeService;
49 52 import org.thingsboard.server.dao.entityview.EntityViewService;
50 53 import org.thingsboard.server.dao.rule.RuleChainService;
51 54 import org.thingsboard.server.dao.tenant.TenantService;
... ... @@ -72,6 +75,7 @@ public class AccessValidator {
72 75 public static final String CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "Customer user is not allowed to perform this operation!";
73 76 public static final String SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "System administrator is not allowed to perform this operation!";
74 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 79 public static final String ENTITY_VIEW_WITH_REQUESTED_ID_NOT_FOUND = "Entity-view with requested id wasn't found!";
76 80
77 81 @Autowired
... ... @@ -99,6 +103,9 @@ public class AccessValidator {
99 103 protected EntityViewService entityViewService;
100 104
101 105 @Autowired
  106 + protected EdgeService edgeService;
  107 +
  108 + @Autowired
102 109 protected AccessControlService accessControlService;
103 110
104 111 private ExecutorService executor;
... ... @@ -174,6 +181,9 @@ public class AccessValidator {
174 181 case ENTITY_VIEW:
175 182 validateEntityView(currentUser, operation, entityId, callback);
176 183 return;
  184 + case EDGE:
  185 + validateEdge(currentUser, operation, entityId, callback);
  186 + return;
177 187 default:
178 188 //TODO: add support of other entities
179 189 throw new IllegalStateException("Not Implemented!");
... ... @@ -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 360 private <T, V> FutureCallback<T> getCallback(FutureCallback<ValidationResult> callback, Function<T, ValidationResult<V>> transformer) {
331 361 return new FutureCallback<T>() {
332 362 @Override
... ...
... ... @@ -40,6 +40,7 @@ public class CustomerUserPermissions extends AbstractPermissions {
40 40 put(Resource.USER, userPermissionChecker);
41 41 put(Resource.WIDGETS_BUNDLE, widgetsPermissionChecker);
42 42 put(Resource.WIDGET_TYPE, widgetsPermissionChecker);
  43 + put(Resource.EDGE, customerEntityPermissionChecker);
43 44 }
44 45
45 46 private static final PermissionChecker customerEntityPermissionChecker =
... ...
... ... @@ -267,6 +267,9 @@ caffeine:
267 267 entityViews:
268 268 timeToLiveInMinutes: 1440
269 269 maxSize: 100000
  270 + edges:
  271 + timeToLiveInMinutes: 1440
  272 + maxSize: 100000
270 273 claimDevices:
271 274 timeToLiveInMinutes: 1
272 275 maxSize: 100000
... ...
... ... @@ -5,7 +5,7 @@
5 5 * you may not use this file except in compliance with the License.
6 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 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
... ... @@ -15,39 +15,46 @@
15 15 */
16 16 package org.thingsboard.server.controller;
17 17
  18 +import com.datastax.driver.core.utils.UUIDs;
18 19 import com.fasterxml.jackson.core.type.TypeReference;
19 20 import org.apache.commons.lang3.RandomStringUtils;
20 21 import org.junit.After;
21 22 import org.junit.Assert;
22 23 import org.junit.Before;
23 24 import org.junit.Test;
  25 +import org.thingsboard.server.common.data.Customer;
  26 +import org.thingsboard.server.common.data.EntitySubtype;
24 27 import org.thingsboard.server.common.data.Tenant;
25 28 import org.thingsboard.server.common.data.User;
26 29 import org.thingsboard.server.common.data.edge.Edge;
  30 +import org.thingsboard.server.common.data.id.CustomerId;
27 31 import org.thingsboard.server.common.data.page.TextPageData;
28 32 import org.thingsboard.server.common.data.page.TextPageLink;
29 33 import org.thingsboard.server.common.data.security.Authority;
  34 +import org.thingsboard.server.dao.model.ModelConstants;
30 35
31 36 import java.util.ArrayList;
32 37 import java.util.Collections;
33 38 import java.util.List;
34 39
35 40 import static org.hamcrest.Matchers.containsString;
36   -import static org.junit.Assert.assertEquals;
37 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 44 public abstract class BaseEdgeControllerTest extends AbstractControllerTest {
40 45
41   - private IdComparator<Edge> idComparator;
  46 + private IdComparator<Edge> idComparator = new IdComparator<>();
  47 +
42 48 private Tenant savedTenant;
43 49 private User tenantAdmin;
44 50
45 51 @Before
46 52 public void beforeTest() throws Exception {
47 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 58 Assert.assertNotNull(savedTenant);
52 59
53 60 tenantAdmin = new User();
... ... @@ -56,44 +63,88 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest {
56 63 tenantAdmin.setEmail("tenant2@thingsboard.org");
57 64 tenantAdmin.setFirstName("Joe");
58 65 tenantAdmin.setLastName("Downs");
59   - tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
60 66
  67 + tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
61 68 }
62 69
63 70 @After
64 71 public void afterTest() throws Exception {
65 72 loginSysAdmin();
  73 +
66 74 doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
67 75 .andExpect(status().isOk());
68 76 }
69 77
70 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 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 85 Assert.assertNotNull(savedEdge);
83 86 Assert.assertNotNull(savedEdge.getId());
84 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 94 doPost("/api/edge", savedEdge, Edge.class);
  95 +
89 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 143 @Test
95 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 148 Edge savedEdge = doPost("/api/edge", edge, Edge.class);
98 149
99 150 doDelete("/api/edge/" + savedEdge.getId().getId().toString())
... ... @@ -104,103 +155,523 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest {
104 155 }
105 156
106 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 167 public void testSaveEdgeWithEmptyName() throws Exception {
108 168 Edge edge = new Edge();
  169 + edge.setType("default");
109 170 doPost("/api/edge", edge)
110 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 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 254 List<Edge> edges = new ArrayList<>();
118 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 274 Collections.sort(edges, idComparator);
124 275 Collections.sort(loadedEdges, idComparator);
125 276
126   - assertEquals(edges, loadedEdges);
  277 + Assert.assertEquals(edges, loadedEdges);
127 278 }
128 279
129 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 347 new TypeReference<TextPageData<Edge>>() {
150   - }, new TextPageLink(4, name1));
  348 + }, pageLink);
151 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 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 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 643 if (pageData.hasNext()) {
200 644 pageLink = pageData.getNextPageLink();
201 645 }
202 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 5 * you may not use this file except in compliance with the License.
6 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 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
... ... @@ -16,7 +16,10 @@
16 16 package org.thingsboard.server.dao.edge;
17 17
18 18 import com.google.common.util.concurrent.ListenableFuture;
  19 +import org.thingsboard.server.common.data.EntitySubtype;
19 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 23 import org.thingsboard.server.common.data.id.EdgeId;
21 24 import org.thingsboard.server.common.data.id.TenantId;
22 25 import org.thingsboard.server.common.data.page.TextPageData;
... ... @@ -26,20 +29,49 @@ import java.util.List;
26 29
27 30 public interface EdgeService {
28 31
29   - Edge saveEdge(Edge edge);
30   -
31 32 Edge findEdgeById(TenantId tenantId, EdgeId edgeId);
32 33
33 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 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 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 +
\ No newline at end of file
... ...
... ... @@ -22,6 +22,7 @@ public class CacheConstants {
22 22 public static final String SESSIONS_CACHE = "sessions";
23 23 public static final String ASSET_CACHE = "assets";
24 24 public static final String ENTITY_VIEW_CACHE = "entityViews";
  25 + public static final String EDGE_CACHE = "edges";
25 26 public static final String CLAIM_DEVICES_CACHE = "claimDevices";
26 27 public static final String SECURITY_SETTINGS_CACHE = "securitySettings";
27 28 }
... ...
... ... @@ -39,6 +39,7 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H
39 39 private TenantId tenantId;
40 40 private CustomerId customerId;
41 41 private String name;
  42 + private String type;
42 43 private transient JsonNode configuration;
43 44 private transient JsonNode additionalInfo;
44 45
... ... @@ -54,6 +55,7 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H
54 55 super(edge);
55 56 this.tenantId = edge.getTenantId();
56 57 this.customerId = edge.getCustomerId();
  58 + this.type = edge.getType();
57 59 this.name = edge.getName();
58 60 this.configuration = edge.getConfiguration();
59 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 31 import org.thingsboard.server.dao.asset.AssetService;
32 32 import org.thingsboard.server.dao.dashboard.DashboardService;
33 33 import org.thingsboard.server.dao.device.DeviceService;
  34 +import org.thingsboard.server.dao.edge.EdgeService;
34 35 import org.thingsboard.server.dao.entity.AbstractEntityService;
35 36 import org.thingsboard.server.dao.entityview.EntityViewService;
36 37 import org.thingsboard.server.dao.exception.DataValidationException;
... ... @@ -76,6 +77,9 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
76 77 @Autowired
77 78 private DashboardService dashboardService;
78 79
  80 + @Autowired
  81 + private EdgeService edgeService;
  82 +
79 83 @Override
80 84 public Customer findCustomerById(TenantId tenantId, CustomerId customerId) {
81 85 log.trace("Executing findCustomerById [{}]", customerId);
... ... @@ -118,6 +122,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
118 122 entityViewService.unassignCustomerEntityViews(customer.getTenantId(), customerId);
119 123 assetService.unassignCustomerAssets(customer.getTenantId(), customerId);
120 124 deviceService.unassignCustomerDevices(customer.getTenantId(), customerId);
  125 + edgeService.unassignCustomerEdges(customer.getTenantId(), customerId);
121 126 userService.deleteCustomerUsers(customer.getTenantId(), customerId);
122 127 deleteEntityRelations(tenantId, customerId);
123 128 customerDao.removeById(tenantId, customerId.getId());
... ...
... ... @@ -15,29 +15,53 @@
15 15 */
16 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 20 import com.google.common.util.concurrent.ListenableFuture;
19 21 import lombok.extern.slf4j.Slf4j;
20 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 27 import org.springframework.stereotype.Service;
22 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 32 import org.thingsboard.server.common.data.Tenant;
24 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 36 import org.thingsboard.server.common.data.id.EdgeId;
  37 +import org.thingsboard.server.common.data.id.EntityId;
26 38 import org.thingsboard.server.common.data.id.TenantId;
27 39 import org.thingsboard.server.common.data.page.TextPageData;
28 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 44 import org.thingsboard.server.dao.entity.AbstractEntityService;
30 45 import org.thingsboard.server.dao.exception.DataValidationException;
31 46 import org.thingsboard.server.dao.service.DataValidator;
32 47 import org.thingsboard.server.dao.service.PaginatedRemover;
33 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 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 59 import static org.thingsboard.server.dao.DaoUtil.toUUIDs;
  60 +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
38 61 import static org.thingsboard.server.dao.service.Validator.validateId;
39 62 import static org.thingsboard.server.dao.service.Validator.validateIds;
40 63 import static org.thingsboard.server.dao.service.Validator.validatePageLink;
  64 +import static org.thingsboard.server.dao.service.Validator.validateString;
41 65
42 66 @Service
43 67 @Slf4j
... ... @@ -45,6 +69,7 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic
45 69
46 70 public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
47 71 public static final String INCORRECT_PAGE_LINK = "Incorrect page link ";
  72 + public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId ";
48 73 public static final String INCORRECT_EDGE_ID = "Incorrect edgeId ";
49 74
50 75 @Autowired
... ... @@ -53,12 +78,11 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic
53 78 @Autowired
54 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 87 @Override
64 88 public Edge findEdgeById(TenantId tenantId, EdgeId edgeId) {
... ... @@ -69,73 +93,222 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic
69 93
70 94 @Override
71 95 public ListenableFuture<Edge> findEdgeByIdAsync(TenantId tenantId, EdgeId edgeId) {
72   - log.trace("Executing findEdgeByIdAsync [{}]", edgeId);
  96 + log.trace("Executing findEdgeById [{}]", edgeId);
73 97 validateId(edgeId, INCORRECT_EDGE_ID + edgeId);
74 98 return edgeDao.findByIdAsync(tenantId, edgeId.getId());
75 99 }
76 100
  101 + @Cacheable(cacheNames = EDGE_CACHE, key = "{#tenantId, #name}")
77 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 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 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 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 132 @Override
101 133 public void deleteEdge(TenantId tenantId, EdgeId edgeId) {
102 134 log.trace("Executing deleteEdge [{}]", edgeId);
103 135 validateId(edgeId, INCORRECT_EDGE_ID + edgeId);
  136 +
  137 + Edge edge = edgeDao.findById(tenantId, edgeId.getId());
  138 +
104 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 147 edgeDao.removeById(tenantId, edgeId.getId());
106 148 }
107 149
108 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 179 public void deleteEdgesByTenantId(TenantId tenantId) {
110 180 log.trace("Executing deleteEdgesByTenantId, tenantId [{}]", tenantId);
111 181 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
112 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 262 private DataValidator<Edge> edgeValidator =
116 263 new DataValidator<Edge>() {
117 264
118 265 @Override
119 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 274 @Override
123 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 285 @Override
127 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 290 if (StringUtils.isEmpty(edge.getName())) {
129 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 294 throw new DataValidationException("Edge should be assigned to tenant!");
133 295 } else {
134   - Tenant tenant = tenantDao.findById(tenantId, edge.getTenantId().getId());
  296 + Tenant tenant = tenantDao.findById(edge.getTenantId(), edge.getTenantId().getId());
135 297 if (tenant == null) {
136 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 317
145 318 @Override
146 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 323 @Override
151 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 15 */
16 16 package org.thingsboard.server.dao.edge;
17 17
18   -import com.datastax.driver.core.querybuilder.Select;
19 18 import com.google.common.util.concurrent.ListenableFuture;
20 19 import lombok.extern.slf4j.Slf4j;
21 20 import org.springframework.stereotype.Component;
  21 +import org.thingsboard.server.common.data.EntitySubtype;
22 22 import org.thingsboard.server.common.data.edge.Edge;
23   -import org.thingsboard.server.common.data.id.TenantId;
24 23 import org.thingsboard.server.common.data.page.TextPageLink;
25   -import org.thingsboard.server.dao.DaoUtil;
26 24 import org.thingsboard.server.dao.model.nosql.EdgeEntity;
27 25 import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao;
28 26 import org.thingsboard.server.dao.util.NoSqlDao;
29 27
30   -import java.util.Collections;
31 28 import java.util.List;
  29 +import java.util.Optional;
32 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 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 34 @Component
43 35 @Slf4j
... ... @@ -54,24 +46,44 @@ public class CassandraEdgeDao extends CassandraAbstractSearchTextDao<EdgeEntity,
54 46 return EDGE_COLUMN_FAMILY_NAME;
55 47 }
56 48
  49 +
57 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 60 @Override
68 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 16 package org.thingsboard.server.dao.edge;
17 17
18 18 import com.google.common.util.concurrent.ListenableFuture;
  19 +import org.thingsboard.server.common.data.EntitySubtype;
19 20 import org.thingsboard.server.common.data.edge.Edge;
  21 +import org.thingsboard.server.common.data.id.TenantId;
20 22 import org.thingsboard.server.common.data.page.TextPageLink;
21 23 import org.thingsboard.server.dao.Dao;
22 24
23 25 import java.util.List;
  26 +import java.util.Optional;
24 27 import java.util.UUID;
25 28
26 29 /**
... ... @@ -30,16 +33,34 @@ import java.util.UUID;
30 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 44 * Find edges by tenantId and page link.
34 45 *
35 46 * @param tenantId the tenantId
36 47 * @param pageLink the page link
37 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 65 * @param tenantId the tenantId
45 66 * @param edgeIds the edge Ids
... ... @@ -47,5 +68,53 @@ public interface EdgeDao extends Dao<Edge> {
47 68 */
48 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 354 public static final String EDGE_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
355 355 public static final String EDGE_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY;
356 356 public static final String EDGE_NAME_PROPERTY = "name";
  357 + public static final String EDGE_TYPE_PROPERTY = "type";
357 358 public static final String EDGE_CONFIGURATION_PROPERTY = "configuration";
358 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 37 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CUSTOMER_ID_PROPERTY;
38 38 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_NAME_PROPERTY;
39 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 41 import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY;
41 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 57 @Column(name = EDGE_CUSTOMER_ID_PROPERTY)
57 58 private UUID customerId;
58 59
  60 + @Column(name = EDGE_TYPE_PROPERTY)
  61 + private String type;
  62 +
59 63 @Column(name = EDGE_NAME_PROPERTY)
60 64 private String name;
61 65
... ... @@ -79,6 +83,7 @@ public class EdgeEntity implements SearchTextEntity<Edge> {
79 83 if (edge.getTenantId() != null) {
80 84 this.tenantId = edge.getTenantId().getId();
81 85 }
  86 + this.type = edge.getType();
82 87 this.name = edge.getName();
83 88 this.configuration = edge.getConfiguration();
84 89 this.additionalInfo = edge.getAdditionalInfo();
... ... @@ -99,6 +104,7 @@ public class EdgeEntity implements SearchTextEntity<Edge> {
99 104 if (customerId != null) {
100 105 edge.setCustomerId(new CustomerId(customerId));
101 106 }
  107 + edge.setType(type);
102 108 edge.setName(name);
103 109 edge.setConfiguration(configuration);
104 110 edge.setAdditionalInfo(additionalInfo);
... ...
... ... @@ -40,6 +40,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.EDGE_COLUMN_FAMILY
40 40 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CUSTOMER_ID_PROPERTY;
41 41 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_NAME_PROPERTY;
42 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 44 import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY;
44 45
45 46 @Data
... ... @@ -55,6 +56,9 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity<
55 56 @Column(name = EDGE_CUSTOMER_ID_PROPERTY)
56 57 private String customerId;
57 58
  59 + @Column(name = EDGE_TYPE_PROPERTY)
  60 + private String type;
  61 +
58 62 @Column(name = EDGE_NAME_PROPERTY)
59 63 private String name;
60 64
... ... @@ -80,6 +84,10 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity<
80 84 if (edge.getTenantId() != null) {
81 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 91 this.name = edge.getName();
84 92 this.configuration = edge.getConfiguration();
85 93 this.additionalInfo = edge.getAdditionalInfo();
... ... @@ -109,6 +117,7 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity<
109 117 if (customerId != null) {
110 118 edge.setCustomerId(new CustomerId(UUIDConverter.fromString(customerId)));
111 119 }
  120 + edge.setType(type);
112 121 edge.setName(name);
113 122 edge.setConfiguration(configuration);
114 123 edge.setAdditionalInfo(additionalInfo);
... ...
... ... @@ -5,7 +5,7 @@
5 5 * you may not use this file except in compliance with the License.
6 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 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
... ... @@ -27,13 +27,52 @@ import java.util.List;
27 27 @SqlDao
28 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 77 List<EdgeEntity> findEdgesByTenantIdAndIdIn(String tenantId, List<String> edgeIds);
39 78
... ...
... ... @@ -5,7 +5,7 @@
5 5 * you may not use this file except in compliance with the License.
6 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 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
... ... @@ -20,8 +20,11 @@ import org.springframework.beans.factory.annotation.Autowired;
20 20 import org.springframework.data.domain.PageRequest;
21 21 import org.springframework.data.repository.CrudRepository;
22 22 import org.springframework.stereotype.Component;
  23 +import org.thingsboard.server.common.data.EntitySubtype;
  24 +import org.thingsboard.server.common.data.EntityType;
23 25 import org.thingsboard.server.common.data.UUIDConverter;
24 26 import org.thingsboard.server.common.data.edge.Edge;
  27 +import org.thingsboard.server.common.data.id.TenantId;
25 28 import org.thingsboard.server.common.data.page.TextPageLink;
26 29 import org.thingsboard.server.dao.DaoUtil;
27 30 import org.thingsboard.server.dao.edge.EdgeDao;
... ... @@ -29,8 +32,11 @@ import org.thingsboard.server.dao.model.sql.EdgeEntity;
29 32 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
30 33 import org.thingsboard.server.dao.util.SqlDao;
31 34
  35 +import java.util.ArrayList;
  36 +import java.util.Collections;
32 37 import java.util.List;
33 38 import java.util.Objects;
  39 +import java.util.Optional;
34 40 import java.util.UUID;
35 41
36 42 import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUID;
... ... @@ -45,9 +51,19 @@ public class JpaEdgeDao extends JpaAbstractSearchTextDao<EdgeEntity, Edge> imple
45 51 private EdgeRepository edgeRepository;
46 52
47 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 67 fromTimeUUID(tenantId),
52 68 Objects.toString(pageLink.getTextSearch(), ""),
53 69 pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()),
... ... @@ -60,13 +76,65 @@ public class JpaEdgeDao extends JpaAbstractSearchTextDao<EdgeEntity, Edge> imple
60 76 }
61 77
62 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 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 29 import org.thingsboard.server.dao.customer.CustomerService;
30 30 import org.thingsboard.server.dao.dashboard.DashboardService;
31 31 import org.thingsboard.server.dao.device.DeviceService;
  32 +import org.thingsboard.server.dao.edge.EdgeService;
32 33 import org.thingsboard.server.dao.entity.AbstractEntityService;
33 34 import org.thingsboard.server.dao.entityview.EntityViewService;
34 35 import org.thingsboard.server.dao.exception.DataValidationException;
... ... @@ -77,6 +78,9 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
77 78 @Autowired
78 79 private RuleChainService ruleChainService;
79 80
  81 + @Autowired
  82 + private EdgeService edgeService;
  83 +
80 84 @Override
81 85 public Tenant findTenantById(TenantId tenantId) {
82 86 log.trace("Executing findTenantById [{}]", tenantId);
... ... @@ -109,6 +113,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
109 113 entityViewService.deleteEntityViewsByTenantId(tenantId);
110 114 assetService.deleteAssetsByTenantId(tenantId);
111 115 deviceService.deleteDevicesByTenantId(tenantId);
  116 + edgeService.deleteEdgesByTenantId(tenantId);
112 117 userService.deleteTenantAdmins(tenantId);
113 118 ruleChainService.deleteRuleChainsByTenantId(tenantId);
114 119 tenantDao.removeById(tenantId, tenantId.getId());
... ...
... ... @@ -254,6 +254,7 @@ CREATE TABLE IF NOT EXISTS edge (
254 254 additional_info varchar,
255 255 customer_id varchar(31),
256 256 configuration varchar(10000000),
  257 + type varchar(255),
257 258 name varchar(255),
258 259 search_text varchar(255),
259 260 tenant_id varchar(31)
... ...
... ... @@ -45,6 +45,7 @@ import org.thingsboard.server.dao.customer.CustomerService;
45 45 import org.thingsboard.server.dao.dashboard.DashboardService;
46 46 import org.thingsboard.server.dao.device.DeviceCredentialsService;
47 47 import org.thingsboard.server.dao.device.DeviceService;
  48 +import org.thingsboard.server.dao.edge.EdgeService;
48 49 import org.thingsboard.server.dao.entityview.EntityViewService;
49 50 import org.thingsboard.server.dao.event.EventService;
50 51 import org.thingsboard.server.dao.relation.RelationService;
... ... @@ -122,6 +123,9 @@ public abstract class AbstractServiceTest {
122 123 protected RuleChainService ruleChainService;
123 124
124 125 @Autowired
  126 + protected EdgeService edgeService;
  127 +
  128 + @Autowired
125 129 private ComponentDescriptorService componentDescriptorService;
126 130
127 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 30 caffeine.specs.claimDevices.timeToLiveInMinutes=1440
31 31 caffeine.specs.claimDevices.maxSize=100000
32 32
  33 +caffeine.specs.edges.timeToLiveInMinutes=1440
  34 +caffeine.specs.edges.maxSize=100000
  35 +
33 36 redis.connection.host=localhost
34 37 redis.connection.port=6379
35 38 redis.connection.db=0
... ...