From 39591675f9a94c29d58efcc379c41babd7f1851e Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Mon, 7 Oct 2019 12:54:28 +0300 Subject: [PATCH] Extended Edge controller & service & dao for SQL. Added service test. NoSQL impl - TODO --- .../server/controller/EdgeController.java | 226 ++++++- .../service/security/AccessValidator.java | 30 + .../permission/CustomerUserPermissions.java | 1 + .../src/main/resources/thingsboard.yml | 3 + .../controller/BaseEdgeControllerTest.java | 627 ++++++++++++++--- .../server/dao/edge/EdgeService.java | 44 +- .../server/common/data/CacheConstants.java | 1 + .../server/common/data/edge/Edge.java | 2 + .../common/data/edge/EdgeSearchQuery.java | 43 ++ .../dao/customer/CustomerServiceImpl.java | 5 + .../server/dao/edge/BaseEdgeService.java | 234 ++++++- .../server/dao/edge/CassandraEdgeDao.java | 56 +- .../thingsboard/server/dao/edge/EdgeDao.java | 73 +- .../server/dao/model/ModelConstants.java | 1 + .../server/dao/model/nosql/EdgeEntity.java | 6 + .../server/dao/model/sql/EdgeEntity.java | 9 + .../server/dao/sql/edge/EdgeRepository.java | 55 +- .../server/dao/sql/edge/JpaEdgeDao.java | 84 ++- .../server/dao/tenant/TenantServiceImpl.java | 5 + .../main/resources/sql/schema-entities.sql | 1 + .../dao/service/AbstractServiceTest.java | 4 + .../dao/service/BaseEdgeServiceTest.java | 636 ++++++++++++++++++ .../service/nosql/EdgeServiceNoSqlTest.java | 23 + .../dao/service/sql/EdgeServiceSqlTest.java | 23 + .../resources/application-test.properties | 3 + 25 files changed, 2016 insertions(+), 179 deletions(-) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeSearchQuery.java create mode 100644 dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java create mode 100644 dao/src/test/java/org/thingsboard/server/dao/service/nosql/EdgeServiceNoSqlTest.java create mode 100644 dao/src/test/java/org/thingsboard/server/dao/service/sql/EdgeServiceSqlTest.java diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java index 5580abcc88..1a16fbd4ed 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.controller; +import com.google.common.util.concurrent.ListenableFuture; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; @@ -25,14 +26,22 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; +import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.audit.ActionType; +import org.thingsboard.server.common.data.device.DeviceSearchQuery; import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.edge.EdgeSearchQuery; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.dao.exception.IncorrectParameterException; +import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; @@ -84,25 +93,6 @@ public class EdgeController extends BaseController { } } - - @PreAuthorize("hasAuthority('TENANT_ADMIN')") - @RequestMapping(value = "/edges", params = {"limit"}, method = RequestMethod.GET) - @ResponseBody - public TextPageData getEdges( - @RequestParam int limit, - @RequestParam(required = false) String textSearch, - @RequestParam(required = false) String idOffset, - @RequestParam(required = false) String textOffset) throws ThingsboardException { - try { - accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, Operation.READ); - TenantId tenantId = getCurrentUser().getTenantId(); - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); - return checkNotNull(edgeService.findTenantEdges(tenantId, pageLink)); - } catch (Exception e) { - throw handleException(e); - } - } - @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) @@ -129,35 +119,209 @@ public class EdgeController extends BaseController { } @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/customer/{customerId}/edge/{edgeId}", method = RequestMethod.POST) + @ResponseBody + public Edge assignEdgeToCustomer(@PathVariable("customerId") String strCustomerId, + @PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { + checkParameter("customerId", strCustomerId); + checkParameter(EDGE_ID, strEdgeId); + try { + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); + Customer customer = checkCustomerId(customerId, Operation.READ); + + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); + checkEdgeId(edgeId, Operation.ASSIGN_TO_CUSTOMER); + + Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(getCurrentUser().getTenantId(), edgeId, customerId)); + + logEntityAction(edgeId, savedEdge, + savedEdge.getCustomerId(), + ActionType.ASSIGNED_TO_CUSTOMER, null, strEdgeId, strCustomerId, customer.getName()); + + return savedEdge; + } catch (Exception e) { + logEntityAction(emptyId(EntityType.EDGE), null, + null, + ActionType.ASSIGNED_TO_CUSTOMER, e, strEdgeId, strCustomerId); + throw handleException(e); + } + } + + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/customer/edge/{edgeId}", method = RequestMethod.DELETE) + @ResponseBody + public Edge unassignEdgeFromCustomer(@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { + checkParameter(EDGE_ID, strEdgeId); + try { + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); + Edge edge = checkEdgeId(edgeId, Operation.UNASSIGN_FROM_CUSTOMER); + if (edge.getCustomerId() == null || edge.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { + throw new IncorrectParameterException("Edge isn't assigned to any customer!"); + } + Customer customer = checkCustomerId(edge.getCustomerId(), Operation.READ); + + Edge savedEdge = checkNotNull(edgeService.unassignEdgeFromCustomer(getCurrentUser().getTenantId(), edgeId)); + + logEntityAction(edgeId, edge, + edge.getCustomerId(), + ActionType.UNASSIGNED_FROM_CUSTOMER, null, strEdgeId, customer.getId().toString(), customer.getName()); + + return savedEdge; + } catch (Exception e) { + logEntityAction(emptyId(EntityType.EDGE), null, + null, + ActionType.UNASSIGNED_FROM_CUSTOMER, e, strEdgeId); + throw handleException(e); + } + } + + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/customer/public/edge/{edgeId}", method = RequestMethod.POST) + @ResponseBody + public Edge assignEdgeToPublicCustomer(@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { + checkParameter(EDGE_ID, strEdgeId); + try { + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); + Edge edge = checkEdgeId(edgeId, Operation.ASSIGN_TO_CUSTOMER); + Customer publicCustomer = customerService.findOrCreatePublicCustomer(edge.getTenantId()); + Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(getCurrentUser().getTenantId(), edgeId, publicCustomer.getId())); + + logEntityAction(edgeId, savedEdge, + savedEdge.getCustomerId(), + ActionType.ASSIGNED_TO_CUSTOMER, null, strEdgeId, publicCustomer.getId().toString(), publicCustomer.getName()); + + return savedEdge; + } catch (Exception e) { + logEntityAction(emptyId(EntityType.EDGE), null, + null, + ActionType.ASSIGNED_TO_CUSTOMER, e, strEdgeId); + throw handleException(e); + } + } + + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/tenant/edges", params = {"limit"}, method = RequestMethod.GET) + @ResponseBody + public TextPageData getTenantEdges( + @RequestParam int limit, + @RequestParam(required = false) String type, + @RequestParam(required = false) String textSearch, + @RequestParam(required = false) String idOffset, + @RequestParam(required = false) String textOffset) throws ThingsboardException { + try { + TenantId tenantId = getCurrentUser().getTenantId(); + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); + if (type != null && type.trim().length() > 0) { + return checkNotNull(edgeService.findEdgesByTenantIdAndType(tenantId, type, pageLink)); + } else { + return checkNotNull(edgeService.findEdgesByTenantId(tenantId, pageLink)); + } + } catch (Exception e) { + throw handleException(e); + } + } + + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/tenant/edges", params = {"edgeName"}, method = RequestMethod.GET) + @ResponseBody + public Edge getTenantEdge( + @RequestParam String edgeName) throws ThingsboardException { + try { + TenantId tenantId = getCurrentUser().getTenantId(); + return checkNotNull(edgeService.findEdgeByTenantIdAndName(tenantId, edgeName)); + } catch (Exception e) { + throw handleException(e); + } + } + + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/customer/{customerId}/edges", params = {"limit"}, method = RequestMethod.GET) + @ResponseBody + public TextPageData getCustomerEdges( + @PathVariable("customerId") String strCustomerId, + @RequestParam int limit, + @RequestParam(required = false) String type, + @RequestParam(required = false) String textSearch, + @RequestParam(required = false) String idOffset, + @RequestParam(required = false) String textOffset) throws ThingsboardException { + checkParameter("customerId", strCustomerId); + try { + TenantId tenantId = getCurrentUser().getTenantId(); + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); + checkCustomerId(customerId, Operation.READ); + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); + if (type != null && type.trim().length() > 0) { + return checkNotNull(edgeService.findEdgesByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink)); + } else { + return checkNotNull(edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink)); + } + } catch (Exception e) { + throw handleException(e); + } + } + + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edges", params = {"edgeIds"}, method = RequestMethod.GET) @ResponseBody public List getEdgesByIds( @RequestParam("edgeIds") String[] strEdgeIds) throws ThingsboardException { checkArrayParameter("edgeIds", strEdgeIds); try { - accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, Operation.READ); SecurityUser user = getCurrentUser(); TenantId tenantId = user.getTenantId(); + CustomerId customerId = user.getCustomerId(); List edgeIds = new ArrayList<>(); for (String strEdgeId : strEdgeIds) { edgeIds.add(new EdgeId(toUUID(strEdgeId))); } - List edges = checkNotNull(edgeService.findEdgesByIdsAsync(tenantId, edgeIds).get()); - return filterEdgesByReadPermission(edges); + ListenableFuture> edges; + if (customerId == null || customerId.isNullUid()) { + edges = edgeService.findEdgesByTenantIdAndIdsAsync(tenantId, edgeIds); + } else { + edges = edgeService.findEdgesByTenantIdCustomerIdAndIdsAsync(tenantId, customerId, edgeIds); + } + return checkNotNull(edges.get()); } catch (Exception e) { throw handleException(e); } } - private List filterEdgesByReadPermission(List edges) { - return edges.stream().filter(edge -> { - try { - accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, Operation.READ, edge.getId(), edge); - return true; - } catch (ThingsboardException e) { - return false; - } - }).collect(Collectors.toList()); + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/edges", method = RequestMethod.POST) + @ResponseBody + public List findByQuery(@RequestBody EdgeSearchQuery query) throws ThingsboardException { + checkNotNull(query); + checkNotNull(query.getParameters()); + checkNotNull(query.getEdgeTypes()); + checkEntityId(query.getParameters().getEntityId(), Operation.READ); + try { + List edges = checkNotNull(edgeService.findEdgesByQuery(getCurrentUser().getTenantId(), query).get()); + edges = edges.stream().filter(edge -> { + try { + accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, Operation.READ, edge.getId(), edge); + return true; + } catch (ThingsboardException e) { + return false; + } + }).collect(Collectors.toList()); + return edges; + } catch (Exception e) { + throw handleException(e); + } + } + + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/edge/types", method = RequestMethod.GET) + @ResponseBody + public List getEdgeTypes() throws ThingsboardException { + try { + SecurityUser user = getCurrentUser(); + TenantId tenantId = user.getTenantId(); + ListenableFuture> edgeTypes = edgeService.findEdgeTypesByTenantId(tenantId); + return checkNotNull(edgeTypes.get()); + } catch (Exception e) { + throw handleException(e); + } } } diff --git a/application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java b/application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java index 6b6e2553fa..3688640769 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java +++ b/application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java @@ -29,10 +29,12 @@ import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.EntityViewId; @@ -46,6 +48,7 @@ import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.tenant.TenantService; @@ -72,6 +75,7 @@ public class AccessValidator { public static final String CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "Customer user is not allowed to perform this operation!"; public static final String SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "System administrator is not allowed to perform this operation!"; public static final String DEVICE_WITH_REQUESTED_ID_NOT_FOUND = "Device with requested id wasn't found!"; + public static final String EDGE_WITH_REQUESTED_ID_NOT_FOUND = "Edge with requested id wasn't found!"; public static final String ENTITY_VIEW_WITH_REQUESTED_ID_NOT_FOUND = "Entity-view with requested id wasn't found!"; @Autowired @@ -98,6 +102,9 @@ public class AccessValidator { @Autowired protected EntityViewService entityViewService; + @Autowired + protected EdgeService edgeService; + @Autowired protected AccessControlService accessControlService; @@ -174,6 +181,9 @@ public class AccessValidator { case ENTITY_VIEW: validateEntityView(currentUser, operation, entityId, callback); return; + case EDGE: + validateEdge(currentUser, operation, entityId, callback); + return; default: //TODO: add support of other entities throw new IllegalStateException("Not Implemented!"); @@ -327,6 +337,26 @@ public class AccessValidator { } } + private void validateEdge(final SecurityUser currentUser, Operation operation, EntityId entityId, FutureCallback callback) { + if (currentUser.isSystemAdmin()) { + callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION)); + } else { + ListenableFuture edgeFuture = edgeService.findEdgeByIdAsync(currentUser.getTenantId(), new EdgeId(entityId.getId())); + Futures.addCallback(edgeFuture, getCallback(callback, edge -> { + if (edge == null) { + return ValidationResult.entityNotFound(EDGE_WITH_REQUESTED_ID_NOT_FOUND); + } else { + try { + accessControlService.checkPermission(currentUser, Resource.EDGE, operation, entityId, edge); + } catch (ThingsboardException e) { + return ValidationResult.accessDenied(e.getMessage()); + } + return ValidationResult.ok(edge); + } + }), executor); + } + } + private FutureCallback getCallback(FutureCallback callback, Function> transformer) { return new FutureCallback() { @Override diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java b/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java index 497bc3da2f..29ef62dccd 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java @@ -40,6 +40,7 @@ public class CustomerUserPermissions extends AbstractPermissions { put(Resource.USER, userPermissionChecker); put(Resource.WIDGETS_BUNDLE, widgetsPermissionChecker); put(Resource.WIDGET_TYPE, widgetsPermissionChecker); + put(Resource.EDGE, customerEntityPermissionChecker); } private static final PermissionChecker customerEntityPermissionChecker = diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 48e37dd646..58fe7bfa9c 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -267,6 +267,9 @@ caffeine: entityViews: timeToLiveInMinutes: 1440 maxSize: 100000 + edges: + timeToLiveInMinutes: 1440 + maxSize: 100000 claimDevices: timeToLiveInMinutes: 1 maxSize: 100000 diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java index d4b25763f8..9eca138e7e 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -15,39 +15,46 @@ */ package org.thingsboard.server.controller; +import com.datastax.driver.core.utils.UUIDs; import com.fasterxml.jackson.core.type.TypeReference; import org.apache.commons.lang3.RandomStringUtils; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.dao.model.ModelConstants; import java.util.ArrayList; import java.util.Collections; import java.util.List; import static org.hamcrest.Matchers.containsString; -import static org.junit.Assert.assertEquals; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; public abstract class BaseEdgeControllerTest extends AbstractControllerTest { - private IdComparator idComparator; + private IdComparator idComparator = new IdComparator<>(); + private Tenant savedTenant; private User tenantAdmin; @Before public void beforeTest() throws Exception { loginSysAdmin(); - idComparator = new IdComparator<>(); - savedTenant = doPost("/api/tenant", getNewTenant("My tenant"), Tenant.class); + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + savedTenant = doPost("/api/tenant", tenant, Tenant.class); Assert.assertNotNull(savedTenant); tenantAdmin = new User(); @@ -56,44 +63,88 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest { tenantAdmin.setEmail("tenant2@thingsboard.org"); tenantAdmin.setFirstName("Joe"); tenantAdmin.setLastName("Downs"); - tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); + tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); } @After public void afterTest() throws Exception { loginSysAdmin(); + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) .andExpect(status().isOk()); } - @Test - public void testFindEdgeById() throws Exception { - Edge savedEdge = getNewSavedEdge("Test edge"); - Edge foundEdge = doGet("/api/edge/" + savedEdge.getId().getId().toString(), Edge.class); - Assert.assertNotNull(foundEdge); - assertEquals(savedEdge, foundEdge); - } - @Test public void testSaveEdge() throws Exception { - Edge savedEdge = getNewSavedEdge("Test edge"); + Edge edge = new Edge(); + edge.setName("My edge"); + edge.setType("default"); + Edge savedEdge = doPost("/api/edge", edge, Edge.class); Assert.assertNotNull(savedEdge); Assert.assertNotNull(savedEdge.getId()); Assert.assertTrue(savedEdge.getCreatedTime() > 0); - assertEquals(savedTenant.getId(), savedEdge.getTenantId()); + Assert.assertEquals(savedTenant.getId(), savedEdge.getTenantId()); + Assert.assertNotNull(savedEdge.getCustomerId()); + Assert.assertEquals(NULL_UUID, savedEdge.getCustomerId().getId()); + Assert.assertEquals(edge.getName(), savedEdge.getName()); - savedEdge.setName("New test edge"); + savedEdge.setName("My new edge"); doPost("/api/edge", savedEdge, Edge.class); + Edge foundEdge = doGet("/api/edge/" + savedEdge.getId().getId().toString(), Edge.class); + Assert.assertEquals(foundEdge.getName(), savedEdge.getName()); + } - assertEquals(foundEdge.getName(), savedEdge.getName()); + @Test + public void testFindEdgeById() throws Exception { + Edge edge = new Edge(); + edge.setName("My edge"); + edge.setType("default"); + Edge savedEdge = doPost("/api/edge", edge, Edge.class); + Edge foundEdge = doGet("/api/edge/" + savedEdge.getId().getId().toString(), Edge.class); + Assert.assertNotNull(foundEdge); + Assert.assertEquals(savedEdge, foundEdge); + } + + @Test + public void testFindEdgeTypesByTenantId() throws Exception { + List edges = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + Edge edge = new Edge(); + edge.setName("My edge B" + i); + edge.setType("typeB"); + edges.add(doPost("/api/edge", edge, Edge.class)); + } + for (int i = 0; i < 7; i++) { + Edge edge = new Edge(); + edge.setName("My edge C" + i); + edge.setType("typeC"); + edges.add(doPost("/api/edge", edge, Edge.class)); + } + for (int i = 0; i < 9; i++) { + Edge edge = new Edge(); + edge.setName("My edge A" + i); + edge.setType("typeA"); + edges.add(doPost("/api/edge", edge, Edge.class)); + } + List edgeTypes = doGetTyped("/api/edge/types", + new TypeReference>() { + }); + + Assert.assertNotNull(edgeTypes); + Assert.assertEquals(3, edgeTypes.size()); + Assert.assertEquals("typeA", edgeTypes.get(0).getType()); + Assert.assertEquals("typeB", edgeTypes.get(1).getType()); + Assert.assertEquals("typeC", edgeTypes.get(2).getType()); } @Test public void testDeleteEdge() throws Exception { - Edge edge = getNewSavedEdge("Test edge"); + Edge edge = new Edge(); + edge.setName("My edge"); + edge.setType("default"); Edge savedEdge = doPost("/api/edge", edge, Edge.class); doDelete("/api/edge/" + savedEdge.getId().getId().toString()) @@ -103,104 +154,524 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest { .andExpect(status().isNotFound()); } + @Test + public void testSaveEdgeWithEmptyType() throws Exception { + Edge edge = new Edge(); + edge.setName("My edge"); + doPost("/api/edge", edge) + .andExpect(status().isBadRequest()) + .andExpect(statusReason(containsString("Edge type should be specified"))); + } + @Test public void testSaveEdgeWithEmptyName() throws Exception { Edge edge = new Edge(); + edge.setType("default"); doPost("/api/edge", edge) .andExpect(status().isBadRequest()) - .andExpect(statusReason(containsString("Edge name should be specified!"))); + .andExpect(statusReason(containsString("Edge name should be specified"))); + } + + @Test + public void testAssignUnassignEdgeToCustomer() throws Exception { + Edge edge = new Edge(); + edge.setName("My edge"); + edge.setType("default"); + Edge savedEdge = doPost("/api/edge", edge, Edge.class); + + Customer customer = new Customer(); + customer.setTitle("My customer"); + Customer savedCustomer = doPost("/api/customer", customer, Customer.class); + + Edge assignedEdge = doPost("/api/customer/" + savedCustomer.getId().getId().toString() + + "/edge/" + savedEdge.getId().getId().toString(), Edge.class); + Assert.assertEquals(savedCustomer.getId(), assignedEdge.getCustomerId()); + + Edge foundEdge = doGet("/api/edge/" + savedEdge.getId().getId().toString(), Edge.class); + Assert.assertEquals(savedCustomer.getId(), foundEdge.getCustomerId()); + + Edge unassignedEdge = + doDelete("/api/customer/edge/" + savedEdge.getId().getId().toString(), Edge.class); + Assert.assertEquals(ModelConstants.NULL_UUID, unassignedEdge.getCustomerId().getId()); + + foundEdge = doGet("/api/edge/" + savedEdge.getId().getId().toString(), Edge.class); + Assert.assertEquals(ModelConstants.NULL_UUID, foundEdge.getCustomerId().getId()); } @Test - public void testGetEdges() throws Exception { + public void testAssignEdgeToNonExistentCustomer() throws Exception { + Edge edge = new Edge(); + edge.setName("My edge"); + edge.setType("default"); + Edge savedEdge = doPost("/api/edge", edge, Edge.class); + doPost("/api/customer/" + UUIDs.timeBased().toString() + + "/edge/" + savedEdge.getId().getId().toString()) + .andExpect(status().isNotFound()); + } + + @Test + public void testAssignEdgeToCustomerFromDifferentTenant() throws Exception { + loginSysAdmin(); + + Tenant tenant2 = new Tenant(); + tenant2.setTitle("Different tenant"); + Tenant savedTenant2 = doPost("/api/tenant", tenant2, Tenant.class); + Assert.assertNotNull(savedTenant2); + + User tenantAdmin2 = new User(); + tenantAdmin2.setAuthority(Authority.TENANT_ADMIN); + tenantAdmin2.setTenantId(savedTenant2.getId()); + tenantAdmin2.setEmail("tenant3@thingsboard.org"); + tenantAdmin2.setFirstName("Joe"); + tenantAdmin2.setLastName("Downs"); + + tenantAdmin2 = createUserAndLogin(tenantAdmin2, "testPassword1"); + + Customer customer = new Customer(); + customer.setTitle("Different customer"); + Customer savedCustomer = doPost("/api/customer", customer, Customer.class); + + login(tenantAdmin.getEmail(), "testPassword1"); + + Edge edge = new Edge(); + edge.setName("My edge"); + edge.setType("default"); + Edge savedEdge = doPost("/api/edge", edge, Edge.class); + + doPost("/api/customer/" + savedCustomer.getId().getId().toString() + + "/edge/" + savedEdge.getId().getId().toString()) + .andExpect(status().isForbidden()); + + loginSysAdmin(); + + doDelete("/api/tenant/" + savedTenant2.getId().getId().toString()) + .andExpect(status().isOk()); + } + + @Test + public void testFindTenantEdges() throws Exception { List edges = new ArrayList<>(); for (int i = 0; i < 178; i++) { - edges.add(getNewSavedEdge("Test edge " + i)); + Edge edge = new Edge(); + edge.setName("Edge" + i); + edge.setType("default"); + edges.add(doPost("/api/edge", edge, Edge.class)); } - List loadedEdges = loadListOf(new TextPageLink(23), "/api/edges?"); + List loadedEdges = new ArrayList<>(); + TextPageLink pageLink = new TextPageLink(23); + TextPageData pageData = null; + do { + pageData = doGetTypedWithPageLink("/api/tenant/edges?", + new TypeReference>() { + }, pageLink); + loadedEdges.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageData.getNextPageLink(); + } + } while (pageData.hasNext()); Collections.sort(edges, idComparator); Collections.sort(loadedEdges, idComparator); - assertEquals(edges, loadedEdges); + Assert.assertEquals(edges, loadedEdges); } @Test - public void testGetEdgesByName() throws Exception { - String name1 = "Entity edge1"; - List namesOfEdge1 = fillListOf(143, name1); - List loadedNamesOfEdge1 = loadListOf(new TextPageLink(15, name1), "/api/edges?"); - Collections.sort(namesOfEdge1, idComparator); - Collections.sort(loadedNamesOfEdge1, idComparator); - assertEquals(namesOfEdge1, loadedNamesOfEdge1); - - String name2 = "Entity edge2"; - List namesOfEdge2 = fillListOf(75, name2); - List loadedNamesOfEdge2 = loadListOf(new TextPageLink(4, name2), "/api/edges?"); - Collections.sort(namesOfEdge2, idComparator); - Collections.sort(loadedNamesOfEdge2, idComparator); - assertEquals(namesOfEdge2, loadedNamesOfEdge2); - - for (Edge edge : loadedNamesOfEdge1) { - doDelete("/api/edge/" + edge.getId().getId().toString()).andExpect(status().isOk()); - } - TextPageData pageData = doGetTypedWithPageLink("/api/edges?", + public void testFindTenantEdgesByName() throws Exception { + String title1 = "Edge title 1"; + List edgesTitle1 = new ArrayList<>(); + for (int i = 0; i < 143; i++) { + Edge edge = new Edge(); + String suffix = RandomStringUtils.randomAlphanumeric(15); + String name = title1 + suffix; + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); + edge.setName(name); + edge.setType("default"); + edgesTitle1.add(doPost("/api/edge", edge, Edge.class)); + } + String title2 = "Edge title 2"; + List edgesTitle2 = new ArrayList<>(); + for (int i = 0; i < 75; i++) { + Edge edge = new Edge(); + String suffix = RandomStringUtils.randomAlphanumeric(15); + String name = title2 + suffix; + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); + edge.setName(name); + edge.setType("default"); + edgesTitle2.add(doPost("/api/edge", edge, Edge.class)); + } + + List loadedEdgesTitle1 = new ArrayList<>(); + TextPageLink pageLink = new TextPageLink(15, title1); + TextPageData pageData = null; + do { + pageData = doGetTypedWithPageLink("/api/tenant/edges?", + new TypeReference>() { + }, pageLink); + loadedEdgesTitle1.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageData.getNextPageLink(); + } + } while (pageData.hasNext()); + + Collections.sort(edgesTitle1, idComparator); + Collections.sort(loadedEdgesTitle1, idComparator); + + Assert.assertEquals(edgesTitle1, loadedEdgesTitle1); + + List loadedEdgesTitle2 = new ArrayList<>(); + pageLink = new TextPageLink(4, title2); + do { + pageData = doGetTypedWithPageLink("/api/tenant/edges?", + new TypeReference>() { + }, pageLink); + loadedEdgesTitle2.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageData.getNextPageLink(); + } + } while (pageData.hasNext()); + + Collections.sort(edgesTitle2, idComparator); + Collections.sort(loadedEdgesTitle2, idComparator); + + Assert.assertEquals(edgesTitle2, loadedEdgesTitle2); + + for (Edge edge : loadedEdgesTitle1) { + doDelete("/api/edge/" + edge.getId().getId().toString()) + .andExpect(status().isOk()); + } + + pageLink = new TextPageLink(4, title1); + pageData = doGetTypedWithPageLink("/api/tenant/edges?", new TypeReference>() { - }, new TextPageLink(4, name1)); + }, pageLink); Assert.assertFalse(pageData.hasNext()); - assertEquals(0, pageData.getData().size()); + Assert.assertEquals(0, pageData.getData().size()); - for (Edge edge : loadedNamesOfEdge2) { - doDelete("/api/edge/" + edge.getId().getId().toString()).andExpect(status().isOk()); + for (Edge edge : loadedEdgesTitle2) { + doDelete("/api/edge/" + edge.getId().getId().toString()) + .andExpect(status().isOk()); } - pageData = doGetTypedWithPageLink("/api/edges?", new TypeReference>() { - }, new TextPageLink(4, name2)); + + pageLink = new TextPageLink(4, title2); + pageData = doGetTypedWithPageLink("/api/tenant/edges?", + new TypeReference>() { + }, pageLink); Assert.assertFalse(pageData.hasNext()); - assertEquals(0, pageData.getData().size()); + Assert.assertEquals(0, pageData.getData().size()); } - private Edge getNewSavedEdge(String name) throws Exception { - Edge edge = createEdge(name); - return doPost("/api/edge", edge, Edge.class); - } + @Test + public void testFindTenantEdgesByType() throws Exception { + String title1 = "Edge title 1"; + String type1 = "typeA"; + List edgesType1 = new ArrayList<>(); + for (int i = 0; i < 143; i++) { + Edge edge = new Edge(); + String suffix = RandomStringUtils.randomAlphanumeric(15); + String name = title1 + suffix; + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); + edge.setName(name); + edge.setType(type1); + edgesType1.add(doPost("/api/edge", edge, Edge.class)); + } + String title2 = "Edge title 2"; + String type2 = "typeB"; + List edgesType2 = new ArrayList<>(); + for (int i = 0; i < 75; i++) { + Edge edge = new Edge(); + String suffix = RandomStringUtils.randomAlphanumeric(15); + String name = title2 + suffix; + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); + edge.setName(name); + edge.setType(type2); + edgesType2.add(doPost("/api/edge", edge, Edge.class)); + } - private Edge createEdge(String name) { - Edge edge = new Edge(); - edge.setTenantId(savedTenant.getId()); - edge.setName(name); - return edge; + List loadedEdgesType1 = new ArrayList<>(); + TextPageLink pageLink = new TextPageLink(15); + TextPageData pageData = null; + do { + pageData = doGetTypedWithPageLink("/api/tenant/edges?type={type}&", + new TypeReference>() { + }, pageLink, type1); + loadedEdgesType1.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageData.getNextPageLink(); + } + } while (pageData.hasNext()); + + Collections.sort(edgesType1, idComparator); + Collections.sort(loadedEdgesType1, idComparator); + + Assert.assertEquals(edgesType1, loadedEdgesType1); + + List loadedEdgesType2 = new ArrayList<>(); + pageLink = new TextPageLink(4); + do { + pageData = doGetTypedWithPageLink("/api/tenant/edges?type={type}&", + new TypeReference>() { + }, pageLink, type2); + loadedEdgesType2.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageData.getNextPageLink(); + } + } while (pageData.hasNext()); + + Collections.sort(edgesType2, idComparator); + Collections.sort(loadedEdgesType2, idComparator); + + Assert.assertEquals(edgesType2, loadedEdgesType2); + + for (Edge edge : loadedEdgesType1) { + doDelete("/api/edge/" + edge.getId().getId().toString()) + .andExpect(status().isOk()); + } + + pageLink = new TextPageLink(4); + pageData = doGetTypedWithPageLink("/api/tenant/edges?type={type}&", + new TypeReference>() { + }, pageLink, type1); + Assert.assertFalse(pageData.hasNext()); + Assert.assertEquals(0, pageData.getData().size()); + + for (Edge edge : loadedEdgesType2) { + doDelete("/api/edge/" + edge.getId().getId().toString()) + .andExpect(status().isOk()); + } + + pageLink = new TextPageLink(4); + pageData = doGetTypedWithPageLink("/api/tenant/edges?type={type}&", + new TypeReference>() { + }, pageLink, type2); + Assert.assertFalse(pageData.hasNext()); + Assert.assertEquals(0, pageData.getData().size()); } - private Tenant getNewTenant(String title) { - Tenant tenant = new Tenant(); - tenant.setTitle(title); - return tenant; + @Test + public void testFindCustomerEdges() throws Exception { + Customer customer = new Customer(); + customer.setTitle("Test customer"); + customer = doPost("/api/customer", customer, Customer.class); + CustomerId customerId = customer.getId(); + + List edges = new ArrayList<>(); + for (int i = 0; i < 128; i++) { + Edge edge = new Edge(); + edge.setName("Edge" + i); + edge.setType("default"); + edge = doPost("/api/edge", edge, Edge.class); + edges.add(doPost("/api/customer/" + customerId.getId().toString() + + "/edge/" + edge.getId().getId().toString(), Edge.class)); + } + + List loadedEdges = new ArrayList<>(); + TextPageLink pageLink = new TextPageLink(23); + TextPageData pageData = null; + do { + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?", + new TypeReference>() { + }, pageLink); + loadedEdges.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageData.getNextPageLink(); + } + } while (pageData.hasNext()); + + Collections.sort(edges, idComparator); + Collections.sort(loadedEdges, idComparator); + + Assert.assertEquals(edges, loadedEdges); } - private List fillListOf(int limit, String partOfName) throws Exception { - List edgeNames = new ArrayList<>(); - for (int i = 0; i < limit; i++) { - String fullName = partOfName + ' ' + RandomStringUtils.randomAlphanumeric(15); - fullName = i % 2 == 0 ? fullName.toLowerCase() : fullName.toUpperCase(); - Edge edge = getNewSavedEdge(fullName); - edgeNames.add(doPost("/api/edge", edge, Edge.class)); + @Test + public void testFindCustomerEdgesByName() throws Exception { + Customer customer = new Customer(); + customer.setTitle("Test customer"); + customer = doPost("/api/customer", customer, Customer.class); + CustomerId customerId = customer.getId(); + + String title1 = "Edge title 1"; + List edgesTitle1 = new ArrayList<>(); + for (int i = 0; i < 125; i++) { + Edge edge = new Edge(); + String suffix = RandomStringUtils.randomAlphanumeric(15); + String name = title1 + suffix; + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); + edge.setName(name); + edge.setType("default"); + edge = doPost("/api/edge", edge, Edge.class); + edgesTitle1.add(doPost("/api/customer/" + customerId.getId().toString() + + "/edge/" + edge.getId().getId().toString(), Edge.class)); + } + String title2 = "Edge title 2"; + List edgesTitle2 = new ArrayList<>(); + for (int i = 0; i < 143; i++) { + Edge edge = new Edge(); + String suffix = RandomStringUtils.randomAlphanumeric(15); + String name = title2 + suffix; + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); + edge.setName(name); + edge.setType("default"); + edge = doPost("/api/edge", edge, Edge.class); + edgesTitle2.add(doPost("/api/customer/" + customerId.getId().toString() + + "/edge/" + edge.getId().getId().toString(), Edge.class)); + } + + List loadedEdgesTitle1 = new ArrayList<>(); + TextPageLink pageLink = new TextPageLink(15, title1); + TextPageData pageData = null; + do { + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?", + new TypeReference>() { + }, pageLink); + loadedEdgesTitle1.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageData.getNextPageLink(); + } + } while (pageData.hasNext()); + + Collections.sort(edgesTitle1, idComparator); + Collections.sort(loadedEdgesTitle1, idComparator); + + Assert.assertEquals(edgesTitle1, loadedEdgesTitle1); + + List loadedEdgesTitle2 = new ArrayList<>(); + pageLink = new TextPageLink(4, title2); + do { + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?", + new TypeReference>() { + }, pageLink); + loadedEdgesTitle2.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageData.getNextPageLink(); + } + } while (pageData.hasNext()); + + Collections.sort(edgesTitle2, idComparator); + Collections.sort(loadedEdgesTitle2, idComparator); + + Assert.assertEquals(edgesTitle2, loadedEdgesTitle2); + + for (Edge edge : loadedEdgesTitle1) { + doDelete("/api/customer/edge/" + edge.getId().getId().toString()) + .andExpect(status().isOk()); + } + + pageLink = new TextPageLink(4, title1); + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?", + new TypeReference>() { + }, pageLink); + Assert.assertFalse(pageData.hasNext()); + Assert.assertEquals(0, pageData.getData().size()); + + for (Edge edge : loadedEdgesTitle2) { + doDelete("/api/customer/edge/" + edge.getId().getId().toString()) + .andExpect(status().isOk()); } - return edgeNames; + + pageLink = new TextPageLink(4, title2); + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?", + new TypeReference>() { + }, pageLink); + Assert.assertFalse(pageData.hasNext()); + Assert.assertEquals(0, pageData.getData().size()); } - private List loadListOf(TextPageLink pageLink, String urlTemplate) throws Exception { - List loadedItems = new ArrayList<>(); - TextPageData pageData; + @Test + public void testFindCustomerEdgesByType() throws Exception { + Customer customer = new Customer(); + customer.setTitle("Test customer"); + customer = doPost("/api/customer", customer, Customer.class); + CustomerId customerId = customer.getId(); + + String title1 = "Edge title 1"; + String type1 = "typeC"; + List edgesType1 = new ArrayList<>(); + for (int i = 0; i < 125; i++) { + Edge edge = new Edge(); + String suffix = RandomStringUtils.randomAlphanumeric(15); + String name = title1 + suffix; + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); + edge.setName(name); + edge.setType(type1); + edge = doPost("/api/edge", edge, Edge.class); + edgesType1.add(doPost("/api/customer/" + customerId.getId().toString() + + "/edge/" + edge.getId().getId().toString(), Edge.class)); + } + String title2 = "Edge title 2"; + String type2 = "typeD"; + List edgesType2 = new ArrayList<>(); + for (int i = 0; i < 143; i++) { + Edge edge = new Edge(); + String suffix = RandomStringUtils.randomAlphanumeric(15); + String name = title2 + suffix; + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); + edge.setName(name); + edge.setType(type2); + edge = doPost("/api/edge", edge, Edge.class); + edgesType2.add(doPost("/api/customer/" + customerId.getId().toString() + + "/edge/" + edge.getId().getId().toString(), Edge.class)); + } + + List loadedEdgesType1 = new ArrayList<>(); + TextPageLink pageLink = new TextPageLink(15); + TextPageData pageData = null; + do { + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?type={type}&", + new TypeReference>() { + }, pageLink, type1); + loadedEdgesType1.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageData.getNextPageLink(); + } + } while (pageData.hasNext()); + + Collections.sort(edgesType1, idComparator); + Collections.sort(loadedEdgesType1, idComparator); + + Assert.assertEquals(edgesType1, loadedEdgesType1); + + List loadedEdgesType2 = new ArrayList<>(); + pageLink = new TextPageLink(4); do { - pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference>() { - }, pageLink); - loadedItems.addAll(pageData.getData()); + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?type={type}&", + new TypeReference>() { + }, pageLink, type2); + loadedEdgesType2.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageData.getNextPageLink(); } } while (pageData.hasNext()); - return loadedItems; + Collections.sort(edgesType2, idComparator); + Collections.sort(loadedEdgesType2, idComparator); + + Assert.assertEquals(edgesType2, loadedEdgesType2); + + for (Edge edge : loadedEdgesType1) { + doDelete("/api/customer/edge/" + edge.getId().getId().toString()) + .andExpect(status().isOk()); + } + + pageLink = new TextPageLink(4); + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?type={type}&", + new TypeReference>() { + }, pageLink, type1); + Assert.assertFalse(pageData.hasNext()); + Assert.assertEquals(0, pageData.getData().size()); + + for (Edge edge : loadedEdgesType2) { + doDelete("/api/customer/edge/" + edge.getId().getId().toString()) + .andExpect(status().isOk()); + } + + pageLink = new TextPageLink(4); + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?type={type}&", + new TypeReference>() { + }, pageLink, type2); + Assert.assertFalse(pageData.hasNext()); + Assert.assertEquals(0, pageData.getData().size()); } } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java index 00c0ee05f5..d01411fb16 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,7 +16,10 @@ package org.thingsboard.server.dao.edge; import com.google.common.util.concurrent.ListenableFuture; +import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.edge.EdgeSearchQuery; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; @@ -26,20 +29,49 @@ import java.util.List; public interface EdgeService { - Edge saveEdge(Edge edge); - Edge findEdgeById(TenantId tenantId, EdgeId edgeId); ListenableFuture findEdgeByIdAsync(TenantId tenantId, EdgeId edgeId); - ListenableFuture> findEdgesByIdsAsync(TenantId tenantId, List edgeIds); + Edge findEdgeByTenantIdAndName(TenantId tenantId, String name); - List findAllEdges(TenantId tenantId); + Edge saveEdge(Edge edge); - TextPageData findTenantEdges(TenantId tenantId, TextPageLink pageLink); + Edge assignEdgeToCustomer(TenantId tenantId, EdgeId edgeId, CustomerId customerId); + + Edge unassignEdgeFromCustomer(TenantId tenantId, EdgeId edgeId); void deleteEdge(TenantId tenantId, EdgeId edgeId); + TextPageData findEdgesByTenantId(TenantId tenantId, TextPageLink pageLink); + + TextPageData findEdgesByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink); + + ListenableFuture> findEdgesByTenantIdAndIdsAsync(TenantId tenantId, List edgeIds); + void deleteEdgesByTenantId(TenantId tenantId); + TextPageData findEdgesByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink); + + TextPageData findEdgesByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, TextPageLink pageLink); + + ListenableFuture> findEdgesByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List edgeIds); + + void unassignCustomerEdges(TenantId tenantId, CustomerId customerId); + + ListenableFuture> findEdgesByQuery(TenantId tenantId, EdgeSearchQuery query); + + ListenableFuture> findEdgeTypesByTenantId(TenantId tenantId); + } + + + + + + + + + + + \ No newline at end of file diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java b/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java index f15997936c..2fcaf51574 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java @@ -22,6 +22,7 @@ public class CacheConstants { public static final String SESSIONS_CACHE = "sessions"; public static final String ASSET_CACHE = "assets"; public static final String ENTITY_VIEW_CACHE = "entityViews"; + public static final String EDGE_CACHE = "edges"; public static final String CLAIM_DEVICES_CACHE = "claimDevices"; public static final String SECURITY_SETTINGS_CACHE = "securitySettings"; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java b/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java index 3ad3a85e78..5efd284d11 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java @@ -39,6 +39,7 @@ public class Edge extends SearchTextBasedWithAdditionalInfo implements H private TenantId tenantId; private CustomerId customerId; private String name; + private String type; private transient JsonNode configuration; private transient JsonNode additionalInfo; @@ -54,6 +55,7 @@ public class Edge extends SearchTextBasedWithAdditionalInfo implements H super(edge); this.tenantId = edge.getTenantId(); this.customerId = edge.getCustomerId(); + this.type = edge.getType(); this.name = edge.getName(); this.configuration = edge.getConfiguration(); this.additionalInfo = edge.getAdditionalInfo(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeSearchQuery.java b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeSearchQuery.java new file mode 100644 index 0000000000..bc382e5b59 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeSearchQuery.java @@ -0,0 +1,43 @@ +/** + * Copyright © 2016-2019 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.edge; + +import lombok.Data; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.EntityRelationsQuery; +import org.thingsboard.server.common.data.relation.EntityTypeFilter; +import org.thingsboard.server.common.data.relation.RelationsSearchParameters; + +import java.util.Collections; +import java.util.List; + +@Data +public class EdgeSearchQuery { + + private RelationsSearchParameters parameters; + private String relationType; + private List edgeTypes; + + public EntityRelationsQuery toEntitySearchQuery() { + EntityRelationsQuery query = new EntityRelationsQuery(); + query.setParameters(parameters); + query.setFilters( + Collections.singletonList(new EntityTypeFilter(relationType == null ? EntityRelation.CONTAINS_TYPE : relationType, + Collections.singletonList(EntityType.EDGE)))); + return query; + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java index 511e410447..00abc68259 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java @@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.exception.DataValidationException; @@ -76,6 +77,9 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom @Autowired private DashboardService dashboardService; + @Autowired + private EdgeService edgeService; + @Override public Customer findCustomerById(TenantId tenantId, CustomerId customerId) { log.trace("Executing findCustomerById [{}]", customerId); @@ -118,6 +122,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom entityViewService.unassignCustomerEntityViews(customer.getTenantId(), customerId); assetService.unassignCustomerAssets(customer.getTenantId(), customerId); deviceService.unassignCustomerDevices(customer.getTenantId(), customerId); + edgeService.unassignCustomerEdges(customer.getTenantId(), customerId); userService.deleteCustomerUsers(customer.getTenantId(), customerId); deleteEntityRelations(tenantId, customerId); customerDao.removeById(tenantId, customerId.getId()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/BaseEdgeService.java b/dao/src/main/java/org/thingsboard/server/dao/edge/BaseEdgeService.java index 03036cbf9c..ecebfcb8fc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/edge/BaseEdgeService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/edge/BaseEdgeService.java @@ -15,29 +15,53 @@ */ package org.thingsboard.server.dao.edge; +import com.google.common.base.Function; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; +import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.EntitySubtype; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.edge.EdgeSearchQuery; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EdgeId; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.EntitySearchDirection; +import org.thingsboard.server.dao.customer.CustomerDao; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.tenant.TenantDao; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import static org.thingsboard.server.common.data.CacheConstants.EDGE_CACHE; import static org.thingsboard.server.dao.DaoUtil.toUUIDs; +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validateIds; import static org.thingsboard.server.dao.service.Validator.validatePageLink; +import static org.thingsboard.server.dao.service.Validator.validateString; @Service @Slf4j @@ -45,6 +69,7 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; public static final String INCORRECT_PAGE_LINK = "Incorrect page link "; + public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId "; public static final String INCORRECT_EDGE_ID = "Incorrect edgeId "; @Autowired @@ -53,12 +78,11 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic @Autowired private TenantDao tenantDao; - @Override - public Edge saveEdge(Edge edge) { - log.trace("Executing saveEdge [{}]", edge); - edgeValidator.validate(edge, Edge::getTenantId); - return edgeDao.save(edge.getTenantId(), edge); - } + @Autowired + private CustomerDao customerDao; + + @Autowired + private CacheManager cacheManager; @Override public Edge findEdgeById(TenantId tenantId, EdgeId edgeId) { @@ -69,42 +93,88 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic @Override public ListenableFuture findEdgeByIdAsync(TenantId tenantId, EdgeId edgeId) { - log.trace("Executing findEdgeByIdAsync [{}]", edgeId); + log.trace("Executing findEdgeById [{}]", edgeId); validateId(edgeId, INCORRECT_EDGE_ID + edgeId); return edgeDao.findByIdAsync(tenantId, edgeId.getId()); } + @Cacheable(cacheNames = EDGE_CACHE, key = "{#tenantId, #name}") @Override - public ListenableFuture> findEdgesByIdsAsync(TenantId tenantId, List edgeIds) { - log.trace("Executing findEdgesByIdsAsync, tenantId [{}], edgeIds [{}]", tenantId, edgeIds); + public Edge findEdgeByTenantIdAndName(TenantId tenantId, String name) { + log.trace("Executing findEdgeByTenantIdAndName [{}][{}]", tenantId, name); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - validateIds(edgeIds, "Incorrect edgeIds " + edgeIds); - return edgeDao.findEdgesByTenantIdAndIdsAsync(tenantId.getId(), toUUIDs(edgeIds)); + Optional edgeOpt = edgeDao.findEdgeByTenantIdAndName(tenantId.getId(), name); + return edgeOpt.orElse(null); } + @CacheEvict(cacheNames = EDGE_CACHE, key = "{#edge.tenantId, #edge.name}") @Override - public List findAllEdges(TenantId tenantId) { - log.trace("Executing findAllEdges"); - return edgeDao.find(tenantId); + public Edge saveEdge(Edge edge) { + log.trace("Executing saveEdge [{}]", edge); + edgeValidator.validate(edge, Edge::getTenantId); + return edgeDao.save(edge.getTenantId(), edge); } @Override - public TextPageData findTenantEdges(TenantId tenantId, TextPageLink pageLink) { - log.trace("Executing findTenantEdges, tenantId [{}], pageLink [{}]", tenantId, pageLink); - validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); - List edges = edgeDao.findByTenantIdAndPageLink(tenantId.getId(), pageLink); - return new TextPageData<>(edges, pageLink); + public Edge assignEdgeToCustomer(TenantId tenantId, EdgeId edgeId, CustomerId customerId) { + Edge edge = findEdgeById(tenantId, edgeId); + edge.setCustomerId(customerId); + return saveEdge(edge); + } + + @Override + public Edge unassignEdgeFromCustomer(TenantId tenantId, EdgeId edgeId) { + Edge edge = findEdgeById(tenantId, edgeId); + edge.setCustomerId(null); + return saveEdge(edge); } @Override public void deleteEdge(TenantId tenantId, EdgeId edgeId) { log.trace("Executing deleteEdge [{}]", edgeId); validateId(edgeId, INCORRECT_EDGE_ID + edgeId); + + Edge edge = edgeDao.findById(tenantId, edgeId.getId()); + deleteEntityRelations(tenantId, edgeId); + + List list = new ArrayList<>(); + list.add(edge.getTenantId()); + list.add(edge.getName()); + Cache cache = cacheManager.getCache(EDGE_CACHE); + cache.evict(list); + edgeDao.removeById(tenantId, edgeId.getId()); } + @Override + public TextPageData findEdgesByTenantId(TenantId tenantId, TextPageLink pageLink) { + log.trace("Executing findEdgesByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); + List edges = edgeDao.findEdgesByTenantId(tenantId.getId(), pageLink); + return new TextPageData<>(edges, pageLink); + } + + @Override + public TextPageData findEdgesByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink) { + log.trace("Executing findEdgesByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateString(type, "Incorrect type " + type); + validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); + List edges = edgeDao.findEdgesByTenantIdAndType(tenantId.getId(), type, pageLink); + return new TextPageData<>(edges, pageLink); + } + + @Override + public ListenableFuture> findEdgesByTenantIdAndIdsAsync(TenantId tenantId, List edgeIds) { + log.trace("Executing findEdgesByTenantIdAndIdsAsync, tenantId [{}], edgeIds [{}]", tenantId, edgeIds); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateIds(edgeIds, "Incorrect edgeIds " + edgeIds); + return edgeDao.findEdgesByTenantIdAndIdsAsync(tenantId.getId(), toUUIDs(edgeIds)); + } + + @Override public void deleteEdgesByTenantId(TenantId tenantId) { log.trace("Executing deleteEdgesByTenantId, tenantId [{}]", tenantId); @@ -112,30 +182,133 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic tenantEdgesRemover.removeEntities(tenantId, tenantId); } + @Override + public TextPageData findEdgesByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink) { + log.trace("Executing findEdgesByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); + validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); + List edges = edgeDao.findEdgesByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); + return new TextPageData<>(edges, pageLink); + } + + @Override + public TextPageData findEdgesByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, TextPageLink pageLink) { + log.trace("Executing findEdgesByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}], type [{}], pageLink [{}]", tenantId, customerId, type, pageLink); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); + validateString(type, "Incorrect type " + type); + validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); + List edges = edgeDao.findEdgesByTenantIdAndCustomerIdAndType(tenantId.getId(), customerId.getId(), type, pageLink); + return new TextPageData<>(edges, pageLink); + } + + @Override + public ListenableFuture> findEdgesByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List edgeIds) { + log.trace("Executing findEdgesByTenantIdCustomerIdAndIdsAsync, tenantId [{}], customerId [{}], edgeIds [{}]", tenantId, customerId, edgeIds); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); + validateIds(edgeIds, "Incorrect edgeIds " + edgeIds); + return edgeDao.findEdgesByTenantIdCustomerIdAndIdsAsync(tenantId.getId(), + customerId.getId(), toUUIDs(edgeIds)); + } + + @Override + public void unassignCustomerEdges(TenantId tenantId, CustomerId customerId) { + log.trace("Executing unassignCustomerEdges, tenantId [{}], customerId [{}]", tenantId, customerId); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); + customerEdgeUnasigner.removeEntities(tenantId, customerId); + } + + @Override + public ListenableFuture> findEdgesByQuery(TenantId tenantId, EdgeSearchQuery query) { + ListenableFuture> relations = relationService.findByQuery(tenantId, query.toEntitySearchQuery()); + ListenableFuture> edges = Futures.transformAsync(relations, r -> { + EntitySearchDirection direction = query.toEntitySearchQuery().getParameters().getDirection(); + List> futures = new ArrayList<>(); + for (EntityRelation relation : r) { + EntityId entityId = direction == EntitySearchDirection.FROM ? relation.getTo() : relation.getFrom(); + if (entityId.getEntityType() == EntityType.EDGE) { + futures.add(findEdgeByIdAsync(tenantId, new EdgeId(entityId.getId()))); + } + } + return Futures.successfulAsList(futures); + }); + + edges = Futures.transform(edges, new Function, List>() { + @Nullable + @Override + public List apply(@Nullable List edgeList) { + return edgeList == null ? Collections.emptyList() : edgeList.stream().filter(edge -> query.getEdgeTypes().contains(edge.getType())).collect(Collectors.toList()); + } + }); + + return edges; + } + + @Override + public ListenableFuture> findEdgeTypesByTenantId(TenantId tenantId) { + log.trace("Executing findEdgeTypesByTenantId, tenantId [{}]", tenantId); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + ListenableFuture> tenantEdgeTypes = edgeDao.findTenantEdgeTypesAsync(tenantId.getId()); + return Futures.transform(tenantEdgeTypes, + edgeTypes -> { + edgeTypes.sort(Comparator.comparing(EntitySubtype::getType)); + return edgeTypes; + }); + } + private DataValidator edgeValidator = new DataValidator() { @Override protected void validateCreate(TenantId tenantId, Edge edge) { + edgeDao.findEdgeByTenantIdAndName(edge.getTenantId().getId(), edge.getName()).ifPresent( + d -> { + throw new DataValidationException("Edge with such name already exists!"); + } + ); } @Override protected void validateUpdate(TenantId tenantId, Edge edge) { + edgeDao.findEdgeByTenantIdAndName(edge.getTenantId().getId(), edge.getName()).ifPresent( + e -> { + if (!e.getUuidId().equals(edge.getUuidId())) { + throw new DataValidationException("Edge with such name already exists!"); + } + } + ); } @Override protected void validateDataImpl(TenantId tenantId, Edge edge) { + if (StringUtils.isEmpty(edge.getType())) { + throw new DataValidationException("Edge type should be specified!"); + } if (StringUtils.isEmpty(edge.getName())) { throw new DataValidationException("Edge name should be specified!"); } - if (edge.getTenantId() == null || edge.getTenantId().isNullUid()) { + if (edge.getTenantId() == null) { throw new DataValidationException("Edge should be assigned to tenant!"); } else { - Tenant tenant = tenantDao.findById(tenantId, edge.getTenantId().getId()); + Tenant tenant = tenantDao.findById(edge.getTenantId(), edge.getTenantId().getId()); if (tenant == null) { throw new DataValidationException("Edge is referencing to non-existent tenant!"); } } + if (edge.getCustomerId() == null) { + edge.setCustomerId(new CustomerId(NULL_UUID)); + } else if (!edge.getCustomerId().getId().equals(NULL_UUID)) { + Customer customer = customerDao.findById(edge.getTenantId(), edge.getCustomerId().getId()); + if (customer == null) { + throw new DataValidationException("Can't assign edge to non-existent customer!"); + } + if (!customer.getTenantId().getId().equals(edge.getTenantId().getId())) { + throw new DataValidationException("Can't assign edge to customer from different tenant!"); + } + } } }; @@ -144,13 +317,26 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic @Override protected List findEntities(TenantId tenantId, TenantId id, TextPageLink pageLink) { - return edgeDao.findByTenantIdAndPageLink(id.getId(), pageLink); + return edgeDao.findEdgesByTenantId(id.getId(), pageLink); } @Override protected void removeEntity(TenantId tenantId, Edge entity) { - deleteEdge(tenantId, new EdgeId(entity.getId().getId())); + deleteEdge(tenantId, new EdgeId(entity.getUuidId())); } }; + private PaginatedRemover customerEdgeUnasigner = new PaginatedRemover() { + + @Override + protected List findEntities(TenantId tenantId, CustomerId id, TextPageLink pageLink) { + return edgeDao.findEdgesByTenantIdAndCustomerId(tenantId.getId(), id.getId(), pageLink); + } + + @Override + protected void removeEntity(TenantId tenantId, Edge entity) { + unassignEdgeFromCustomer(tenantId, new EdgeId(entity.getUuidId())); + } + }; + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/CassandraEdgeDao.java b/dao/src/main/java/org/thingsboard/server/dao/edge/CassandraEdgeDao.java index 49b3881a9f..90446cf4f8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/edge/CassandraEdgeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/edge/CassandraEdgeDao.java @@ -15,29 +15,21 @@ */ package org.thingsboard.server.dao.edge; -import com.datastax.driver.core.querybuilder.Select; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.edge.Edge; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageLink; -import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.nosql.EdgeEntity; import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao; import org.thingsboard.server.dao.util.NoSqlDao; -import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.UUID; -import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; -import static com.datastax.driver.core.querybuilder.QueryBuilder.in; -import static com.datastax.driver.core.querybuilder.QueryBuilder.select; -import static org.thingsboard.server.dao.model.ModelConstants.EDGE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_COLUMN_FAMILY_NAME; -import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY; -import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY; @Component @Slf4j @@ -54,24 +46,44 @@ public class CassandraEdgeDao extends CassandraAbstractSearchTextDao findByTenantIdAndPageLink(UUID tenantId, TextPageLink pageLink) { - log.debug("Try to find edges by tenantId [{}] and pageLink [{}]", tenantId, pageLink); - List edgeEntities = findPageWithTextSearch(new TenantId(tenantId), EDGE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, - Collections.singletonList(eq(EDGE_TENANT_ID_PROPERTY, tenantId)), pageLink); + public List findEdgesByTenantId(UUID tenantId, TextPageLink pageLink) { + return null; + } - log.trace("Found edges [{}] by tenantId [{}] and pageLink [{}]", edgeEntities, tenantId, pageLink); - return DaoUtil.convertDataList(edgeEntities); + @Override + public List findEdgesByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink) { + return null; } @Override public ListenableFuture> findEdgesByTenantIdAndIdsAsync(UUID tenantId, List edgeIds) { - log.debug("Try to find edges by tenantId [{}] and edge Ids [{}]", tenantId, edgeIds); - Select select = select().from(getColumnFamilyName()); - Select.Where query = select.where(); - query.and(eq(EDGE_TENANT_ID_PROPERTY, tenantId)); - query.and(in(ID_PROPERTY, edgeIds)); - return findListByStatementAsync(new TenantId(tenantId), query); + return null; + } + + @Override + public List findEdgesByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) { + return null; + } + + @Override + public List findEdgesByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink) { + return null; } + @Override + public ListenableFuture> findEdgesByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List edgeIds) { + return null; + } + + @Override + public Optional findEdgeByTenantIdAndName(UUID tenantId, String name) { + return Optional.empty(); + } + + @Override + public ListenableFuture> findTenantEdgeTypesAsync(UUID tenantId) { + return null; + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeDao.java b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeDao.java index 9bb3e9c9b4..4f2d3f85c5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeDao.java @@ -16,11 +16,14 @@ package org.thingsboard.server.dao.edge; import com.google.common.util.concurrent.ListenableFuture; +import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.dao.Dao; import java.util.List; +import java.util.Optional; import java.util.UUID; /** @@ -29,6 +32,14 @@ import java.util.UUID; */ public interface EdgeDao extends Dao { + /** + * Save or update edge object + * + * @param edge the edge object + * @return saved edge object + */ + Edge save(TenantId tenantId, Edge edge); + /** * Find edges by tenantId and page link. * @@ -36,10 +47,20 @@ public interface EdgeDao extends Dao { * @param pageLink the page link * @return the list of edge objects */ - List findByTenantIdAndPageLink(UUID tenantId, TextPageLink pageLink); + List findEdgesByTenantId(UUID tenantId, TextPageLink pageLink); + + /** + * Find edges by tenantId, type and page link. + * + * @param tenantId the tenantId + * @param type the type + * @param pageLink the page link + * @return the list of edge objects + */ + List findEdgesByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink); /** - * Find edges by tenantId and edge Ids. + * Find edges by tenantId and edges Ids. * * @param tenantId the tenantId * @param edgeIds the edge Ids @@ -47,5 +68,53 @@ public interface EdgeDao extends Dao { */ ListenableFuture> findEdgesByTenantIdAndIdsAsync(UUID tenantId, List edgeIds); + /** + * Find edges by tenantId, customerId and page link. + * + * @param tenantId the tenantId + * @param customerId the customerId + * @param pageLink the page link + * @return the list of edge objects + */ + List findEdgesByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink); + + /** + * Find edges by tenantId, customerId, type and page link. + * + * @param tenantId the tenantId + * @param customerId the customerId + * @param type the type + * @param pageLink the page link + * @return the list of edge objects + */ + List findEdgesByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink); + + + /** + * Find edges by tenantId, customerId and edges Ids. + * + * @param tenantId the tenantId + * @param customerId the customerId + * @param edgeIds the edge Ids + * @return the list of edge objects + */ + ListenableFuture> findEdgesByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List edgeIds); + + /** + * Find edges by tenantId and edge name. + * + * @param tenantId the tenantId + * @param name the edge name + * @return the optional edge object + */ + Optional findEdgeByTenantIdAndName(UUID tenantId, String name); + + /** + * Find tenants edge types. + * + * @return the list of tenant edge type objects + */ + ListenableFuture> findTenantEdgeTypesAsync(UUID tenantId); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index 3705a6c276..2fdf80267b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -354,6 +354,7 @@ public class ModelConstants { public static final String EDGE_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; public static final String EDGE_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY; public static final String EDGE_NAME_PROPERTY = "name"; + public static final String EDGE_TYPE_PROPERTY = "type"; public static final String EDGE_CONFIGURATION_PROPERTY = "configuration"; public static final String EDGE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EdgeEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EdgeEntity.java index 0f82323237..ee658e536a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EdgeEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EdgeEntity.java @@ -37,6 +37,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CONFIGURATION import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CUSTOMER_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_NAME_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TYPE_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY; @@ -56,6 +57,9 @@ public class EdgeEntity implements SearchTextEntity { @Column(name = EDGE_CUSTOMER_ID_PROPERTY) private UUID customerId; + @Column(name = EDGE_TYPE_PROPERTY) + private String type; + @Column(name = EDGE_NAME_PROPERTY) private String name; @@ -79,6 +83,7 @@ public class EdgeEntity implements SearchTextEntity { if (edge.getTenantId() != null) { this.tenantId = edge.getTenantId().getId(); } + this.type = edge.getType(); this.name = edge.getName(); this.configuration = edge.getConfiguration(); this.additionalInfo = edge.getAdditionalInfo(); @@ -99,6 +104,7 @@ public class EdgeEntity implements SearchTextEntity { if (customerId != null) { edge.setCustomerId(new CustomerId(customerId)); } + edge.setType(type); edge.setName(name); edge.setConfiguration(configuration); edge.setAdditionalInfo(additionalInfo); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEntity.java index d06e35f1a2..637a069e70 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEntity.java @@ -40,6 +40,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.EDGE_COLUMN_FAMILY import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CUSTOMER_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_NAME_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TYPE_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY; @Data @@ -55,6 +56,9 @@ public class EdgeEntity extends BaseSqlEntity implements SearchTextEntity< @Column(name = EDGE_CUSTOMER_ID_PROPERTY) private String customerId; + @Column(name = EDGE_TYPE_PROPERTY) + private String type; + @Column(name = EDGE_NAME_PROPERTY) private String name; @@ -80,6 +84,10 @@ public class EdgeEntity extends BaseSqlEntity implements SearchTextEntity< if (edge.getTenantId() != null) { this.tenantId = UUIDConverter.fromTimeUUID(edge.getTenantId().getId()); } + if (edge.getCustomerId() != null) { + this.customerId = UUIDConverter.fromTimeUUID(edge.getCustomerId().getId()); + } + this.type = edge.getType(); this.name = edge.getName(); this.configuration = edge.getConfiguration(); this.additionalInfo = edge.getAdditionalInfo(); @@ -109,6 +117,7 @@ public class EdgeEntity extends BaseSqlEntity implements SearchTextEntity< if (customerId != null) { edge.setCustomerId(new CustomerId(UUIDConverter.fromString(customerId))); } + edge.setType(type); edge.setName(name); edge.setConfiguration(configuration); edge.setAdditionalInfo(additionalInfo); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeRepository.java index 498e828501..d688fa5f13 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeRepository.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -27,13 +27,52 @@ import java.util.List; @SqlDao public interface EdgeRepository extends CrudRepository { - @Query("SELECT a FROM EdgeEntity a WHERE a.tenantId = :tenantId " + - "AND LOWER(a.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " + - "AND a.id > :idOffset ORDER BY a.id") - List findByTenantIdAndPageLink(@Param("tenantId") String tenantId, - @Param("textSearch") String textSearch, - @Param("idOffset") String idOffset, - Pageable pageable); + @Query("SELECT d FROM EdgeEntity d WHERE d.tenantId = :tenantId " + + "AND d.customerId = :customerId " + + "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:searchText, '%')) " + + "AND d.id > :idOffset ORDER BY d.id") + List findByTenantIdAndCustomerId(@Param("tenantId") String tenantId, + @Param("customerId") String customerId, + @Param("searchText") String searchText, + @Param("idOffset") String idOffset, + Pageable pageable); + + @Query("SELECT d FROM EdgeEntity d WHERE d.tenantId = :tenantId " + + "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " + + "AND d.id > :idOffset ORDER BY d.id") + List findByTenantId(@Param("tenantId") String tenantId, + @Param("textSearch") String textSearch, + @Param("idOffset") String idOffset, + Pageable pageable); + + @Query("SELECT d FROM EdgeEntity d WHERE d.tenantId = :tenantId " + + "AND d.type = :type " + + "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " + + "AND d.id > :idOffset ORDER BY d.id") + List findByTenantIdAndType(@Param("tenantId") String tenantId, + @Param("type") String type, + @Param("textSearch") String textSearch, + @Param("idOffset") String idOffset, + Pageable pageable); + + @Query("SELECT d FROM EdgeEntity d WHERE d.tenantId = :tenantId " + + "AND d.customerId = :customerId " + + "AND d.type = :type " + + "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " + + "AND d.id > :idOffset ORDER BY d.id") + List findByTenantIdAndCustomerIdAndType(@Param("tenantId") String tenantId, + @Param("customerId") String customerId, + @Param("type") String type, + @Param("textSearch") String textSearch, + @Param("idOffset") String idOffset, + Pageable pageable); + + @Query("SELECT DISTINCT d.type FROM EdgeEntity d WHERE d.tenantId = :tenantId") + List findTenantEdgeTypes(@Param("tenantId") String tenantId); + + EdgeEntity findByTenantIdAndName(String tenantId, String name); + + List findEdgesByTenantIdAndCustomerIdAndIdIn(String tenantId, String customerId, List edgeIds); List findEdgesByTenantIdAndIdIn(String tenantId, List edgeIds); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java index 3d323a4e65..476a4a8e8f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,8 +20,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.PageRequest; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.EntitySubtype; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.UUIDConverter; import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.edge.EdgeDao; @@ -29,8 +32,11 @@ import org.thingsboard.server.dao.model.sql.EdgeEntity; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; import org.thingsboard.server.dao.util.SqlDao; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.UUID; import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUID; @@ -45,9 +51,19 @@ public class JpaEdgeDao extends JpaAbstractSearchTextDao imple private EdgeRepository edgeRepository; @Override - public List findByTenantIdAndPageLink(UUID tenantId, TextPageLink pageLink) { - return DaoUtil.convertDataList(edgeRepository - .findByTenantIdAndPageLink( + protected Class getEntityClass() { + return EdgeEntity.class; + } + + @Override + protected CrudRepository getCrudRepository() { + return edgeRepository; + } + + @Override + public List findEdgesByTenantId(UUID tenantId, TextPageLink pageLink) { + return DaoUtil.convertDataList( + edgeRepository.findByTenantId( fromTimeUUID(tenantId), Objects.toString(pageLink.getTextSearch(), ""), pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), @@ -60,13 +76,65 @@ public class JpaEdgeDao extends JpaAbstractSearchTextDao imple } @Override - protected Class getEntityClass() { - return EdgeEntity.class; + public List findEdgesByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) { + return DaoUtil.convertDataList( + edgeRepository.findByTenantIdAndCustomerId( + fromTimeUUID(tenantId), + fromTimeUUID(customerId), + Objects.toString(pageLink.getTextSearch(), ""), + pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), + new PageRequest(0, pageLink.getLimit()))); } @Override - protected CrudRepository getCrudRepository() { - return edgeRepository; + public ListenableFuture> findEdgesByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List edgeIds) { + return service.submit(() -> DaoUtil.convertDataList( + edgeRepository.findEdgesByTenantIdAndCustomerIdAndIdIn(fromTimeUUID(tenantId), fromTimeUUID(customerId), fromTimeUUIDs(edgeIds)))); + } + + @Override + public Optional findEdgeByTenantIdAndName(UUID tenantId, String name) { + Edge edge = DaoUtil.getData(edgeRepository.findByTenantIdAndName(fromTimeUUID(tenantId), name)); + return Optional.ofNullable(edge); + } + + @Override + public List findEdgesByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink) { + return DaoUtil.convertDataList( + edgeRepository.findByTenantIdAndType( + fromTimeUUID(tenantId), + type, + Objects.toString(pageLink.getTextSearch(), ""), + pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), + new PageRequest(0, pageLink.getLimit()))); + } + + @Override + public List findEdgesByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink) { + return DaoUtil.convertDataList( + edgeRepository.findByTenantIdAndCustomerIdAndType( + fromTimeUUID(tenantId), + fromTimeUUID(customerId), + type, + Objects.toString(pageLink.getTextSearch(), ""), + pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), + new PageRequest(0, pageLink.getLimit()))); + } + + @Override + public ListenableFuture> findTenantEdgeTypesAsync(UUID tenantId) { + return service.submit(() -> convertTenantEdgeTypesToDto(tenantId, edgeRepository.findTenantEdgeTypes(fromTimeUUID(tenantId)))); + } + + private List convertTenantEdgeTypesToDto(UUID tenantId, List types) { + List list = Collections.emptyList(); + if (types != null && !types.isEmpty()) { + list = new ArrayList<>(); + for (String type : types) { + list.add(new EntitySubtype(new TenantId(tenantId), EntityType.EDGE, type)); + } + } + return list; } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index e06e6b0b2c..91b1117d63 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -29,6 +29,7 @@ import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.exception.DataValidationException; @@ -77,6 +78,9 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @Autowired private RuleChainService ruleChainService; + @Autowired + private EdgeService edgeService; + @Override public Tenant findTenantById(TenantId tenantId) { log.trace("Executing findTenantById [{}]", tenantId); @@ -109,6 +113,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe entityViewService.deleteEntityViewsByTenantId(tenantId); assetService.deleteAssetsByTenantId(tenantId); deviceService.deleteDevicesByTenantId(tenantId); + edgeService.deleteEdgesByTenantId(tenantId); userService.deleteTenantAdmins(tenantId); ruleChainService.deleteRuleChainsByTenantId(tenantId); tenantDao.removeById(tenantId, tenantId.getId()); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index a1b0889932..36f4c5c168 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -254,6 +254,7 @@ CREATE TABLE IF NOT EXISTS edge ( additional_info varchar, customer_id varchar(31), configuration varchar(10000000), + type varchar(255), name varchar(255), search_text varchar(255), tenant_id varchar(31) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java index 7b460d5883..c94848ef84 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java @@ -45,6 +45,7 @@ import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.event.EventService; import org.thingsboard.server.dao.relation.RelationService; @@ -121,6 +122,9 @@ public abstract class AbstractServiceTest { @Autowired protected RuleChainService ruleChainService; + @Autowired + protected EdgeService edgeService; + @Autowired private ComponentDescriptorService componentDescriptorService; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java new file mode 100644 index 0000000000..5ce90869d6 --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java @@ -0,0 +1,636 @@ +/** + * Copyright © 2016-2019 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.service; + +import com.datastax.driver.core.utils.UUIDs; +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.EntitySubtype; +import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.TextPageData; +import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.dao.exception.DataValidationException; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; + +public abstract class BaseEdgeServiceTest extends AbstractServiceTest { + + private IdComparator idComparator = new IdComparator<>(); + + private TenantId tenantId; + + @Before + public void before() { + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + Tenant savedTenant = tenantService.saveTenant(tenant); + Assert.assertNotNull(savedTenant); + tenantId = savedTenant.getId(); + } + + @After + public void after() { + tenantService.deleteTenant(tenantId); + } + + @Test + public void testSaveEdge() { + Edge edge = new Edge(); + edge.setTenantId(tenantId); + edge.setName("My edge"); + edge.setType("default"); + Edge savedEdge = edgeService.saveEdge(edge); + + Assert.assertNotNull(savedEdge); + Assert.assertNotNull(savedEdge.getId()); + Assert.assertTrue(savedEdge.getCreatedTime() > 0); + Assert.assertEquals(edge.getTenantId(), savedEdge.getTenantId()); + Assert.assertNotNull(savedEdge.getCustomerId()); + Assert.assertEquals(NULL_UUID, savedEdge.getCustomerId().getId()); + Assert.assertEquals(edge.getName(), savedEdge.getName()); + + savedEdge.setName("My new edge"); + + edgeService.saveEdge(savedEdge); + Edge foundEdge = edgeService.findEdgeById(tenantId, savedEdge.getId()); + Assert.assertEquals(foundEdge.getName(), savedEdge.getName()); + + edgeService.deleteEdge(tenantId, savedEdge.getId()); + } + + @Test(expected = DataValidationException.class) + public void testSaveEdgeWithEmptyName() { + Edge edge = new Edge(); + edge.setType("default"); + edge.setTenantId(tenantId); + edgeService.saveEdge(edge); + } + + @Test(expected = DataValidationException.class) + public void testSaveEdgeWithEmptyTenant() { + Edge edge = new Edge(); + edge.setName("My edge"); + edge.setType("default"); + edgeService.saveEdge(edge); + } + + @Test(expected = DataValidationException.class) + public void testSaveEdgeWithInvalidTenant() { + Edge edge = new Edge(); + edge.setName("My edge"); + edge.setType("default"); + edge.setTenantId(new TenantId(UUIDs.timeBased())); + edgeService.saveEdge(edge); + } + + @Test(expected = DataValidationException.class) + public void testAssignEdgeToNonExistentCustomer() { + Edge edge = new Edge(); + edge.setName("My edge"); + edge.setType("default"); + edge.setTenantId(tenantId); + edge = edgeService.saveEdge(edge); + try { + edgeService.assignEdgeToCustomer(tenantId, edge.getId(), new CustomerId(UUIDs.timeBased())); + } finally { + edgeService.deleteEdge(tenantId, edge.getId()); + } + } + + @Test(expected = DataValidationException.class) + public void testAssignEdgeToCustomerFromDifferentTenant() { + Edge edge = new Edge(); + edge.setName("My edge"); + edge.setType("default"); + edge.setTenantId(tenantId); + edge = edgeService.saveEdge(edge); + Tenant tenant = new Tenant(); + tenant.setTitle("Test different tenant"); + tenant = tenantService.saveTenant(tenant); + Customer customer = new Customer(); + customer.setTenantId(tenant.getId()); + customer.setTitle("Test different customer"); + customer = customerService.saveCustomer(customer); + try { + edgeService.assignEdgeToCustomer(tenantId, edge.getId(), customer.getId()); + } finally { + edgeService.deleteEdge(tenantId, edge.getId()); + tenantService.deleteTenant(tenant.getId()); + } + } + + @Test + public void testFindEdgeById() { + Edge edge = new Edge(); + edge.setTenantId(tenantId); + edge.setName("My edge"); + edge.setType("default"); + Edge savedEdge = edgeService.saveEdge(edge); + Edge foundEdge = edgeService.findEdgeById(tenantId, savedEdge.getId()); + Assert.assertNotNull(foundEdge); + Assert.assertEquals(savedEdge, foundEdge); + edgeService.deleteEdge(tenantId, savedEdge.getId()); + } + + @Test + public void testFindEdgeTypesByTenantId() throws Exception { + List edges = new ArrayList<>(); + try { + for (int i = 0; i < 3; i++) { + Edge edge = new Edge(); + edge.setTenantId(tenantId); + edge.setName("My edge B" + i); + edge.setType("typeB"); + edges.add(edgeService.saveEdge(edge)); + } + for (int i = 0; i < 7; i++) { + Edge edge = new Edge(); + edge.setTenantId(tenantId); + edge.setName("My edge C" + i); + edge.setType("typeC"); + edges.add(edgeService.saveEdge(edge)); + } + for (int i = 0; i < 9; i++) { + Edge edge = new Edge(); + edge.setTenantId(tenantId); + edge.setName("My edge A" + i); + edge.setType("typeA"); + edges.add(edgeService.saveEdge(edge)); + } + List edgeTypes = edgeService.findEdgeTypesByTenantId(tenantId).get(); + Assert.assertNotNull(edgeTypes); + Assert.assertEquals(3, edgeTypes.size()); + Assert.assertEquals("typeA", edgeTypes.get(0).getType()); + Assert.assertEquals("typeB", edgeTypes.get(1).getType()); + Assert.assertEquals("typeC", edgeTypes.get(2).getType()); + } finally { + edges.forEach((edge) -> { + edgeService.deleteEdge(tenantId, edge.getId()); + }); + } + } + + @Test + public void testDeleteEdge() { + Edge edge = new Edge(); + edge.setTenantId(tenantId); + edge.setName("My edge"); + edge.setType("default"); + Edge savedEdge = edgeService.saveEdge(edge); + Edge foundEdge = edgeService.findEdgeById(tenantId, savedEdge.getId()); + Assert.assertNotNull(foundEdge); + edgeService.deleteEdge(tenantId, savedEdge.getId()); + foundEdge = edgeService.findEdgeById(tenantId, savedEdge.getId()); + Assert.assertNull(foundEdge); + } + + @Test + public void testFindEdgesByTenantId() { + Tenant tenant = new Tenant(); + tenant.setTitle("Test tenant"); + tenant = tenantService.saveTenant(tenant); + + TenantId tenantId = tenant.getId(); + + List edges = new ArrayList<>(); + for (int i = 0; i < 178; i++) { + Edge edge = new Edge(); + edge.setTenantId(tenantId); + edge.setName("Edge" + i); + edge.setType("default"); + edges.add(edgeService.saveEdge(edge)); + } + + List loadedEdges = new ArrayList<>(); + TextPageLink pageLink = new TextPageLink(23); + TextPageData pageData = null; + do { + pageData = edgeService.findEdgesByTenantId(tenantId, pageLink); + loadedEdges.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageData.getNextPageLink(); + } + } while (pageData.hasNext()); + + Collections.sort(edges, idComparator); + Collections.sort(loadedEdges, idComparator); + + Assert.assertEquals(edges, loadedEdges); + + edgeService.deleteEdgesByTenantId(tenantId); + + pageLink = new TextPageLink(33); + pageData = edgeService.findEdgesByTenantId(tenantId, pageLink); + Assert.assertFalse(pageData.hasNext()); + Assert.assertTrue(pageData.getData().isEmpty()); + + tenantService.deleteTenant(tenantId); + } + + @Test + public void testFindEdgesByTenantIdAndName() { + String title1 = "Edge title 1"; + List edgesTitle1 = new ArrayList<>(); + for (int i = 0; i < 143; i++) { + Edge edge = new Edge(); + edge.setTenantId(tenantId); + String suffix = RandomStringUtils.randomAlphanumeric(15); + String name = title1 + suffix; + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); + edge.setName(name); + edge.setType("default"); + edgesTitle1.add(edgeService.saveEdge(edge)); + } + String title2 = "Edge title 2"; + List edgesTitle2 = new ArrayList<>(); + for (int i = 0; i < 175; i++) { + Edge edge = new Edge(); + edge.setTenantId(tenantId); + String suffix = RandomStringUtils.randomAlphanumeric(15); + String name = title2 + suffix; + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); + edge.setName(name); + edge.setType("default"); + edgesTitle2.add(edgeService.saveEdge(edge)); + } + + List loadedEdgesTitle1 = new ArrayList<>(); + TextPageLink pageLink = new TextPageLink(15, title1); + TextPageData pageData = null; + do { + pageData = edgeService.findEdgesByTenantId(tenantId, pageLink); + loadedEdgesTitle1.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageData.getNextPageLink(); + } + } while (pageData.hasNext()); + + Collections.sort(edgesTitle1, idComparator); + Collections.sort(loadedEdgesTitle1, idComparator); + + Assert.assertEquals(edgesTitle1, loadedEdgesTitle1); + + List loadedEdgesTitle2 = new ArrayList<>(); + pageLink = new TextPageLink(4, title2); + do { + pageData = edgeService.findEdgesByTenantId(tenantId, pageLink); + loadedEdgesTitle2.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageData.getNextPageLink(); + } + } while (pageData.hasNext()); + + Collections.sort(edgesTitle2, idComparator); + Collections.sort(loadedEdgesTitle2, idComparator); + + Assert.assertEquals(edgesTitle2, loadedEdgesTitle2); + + for (Edge edge : loadedEdgesTitle1) { + edgeService.deleteEdge(tenantId, edge.getId()); + } + + pageLink = new TextPageLink(4, title1); + pageData = edgeService.findEdgesByTenantId(tenantId, pageLink); + Assert.assertFalse(pageData.hasNext()); + Assert.assertEquals(0, pageData.getData().size()); + + for (Edge edge : loadedEdgesTitle2) { + edgeService.deleteEdge(tenantId, edge.getId()); + } + + pageLink = new TextPageLink(4, title2); + pageData = edgeService.findEdgesByTenantId(tenantId, pageLink); + Assert.assertFalse(pageData.hasNext()); + Assert.assertEquals(0, pageData.getData().size()); + } + + @Test + public void testFindEdgesByTenantIdAndType() { + String title1 = "Edge title 1"; + String type1 = "typeA"; + List edgesType1 = new ArrayList<>(); + for (int i = 0; i < 143; i++) { + Edge edge = new Edge(); + edge.setTenantId(tenantId); + String suffix = RandomStringUtils.randomAlphanumeric(15); + String name = title1 + suffix; + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); + edge.setName(name); + edge.setType(type1); + edgesType1.add(edgeService.saveEdge(edge)); + } + String title2 = "Edge title 2"; + String type2 = "typeB"; + List edgesType2 = new ArrayList<>(); + for (int i = 0; i < 175; i++) { + Edge edge = new Edge(); + edge.setTenantId(tenantId); + String suffix = RandomStringUtils.randomAlphanumeric(15); + String name = title2 + suffix; + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); + edge.setName(name); + edge.setType(type2); + edgesType2.add(edgeService.saveEdge(edge)); + } + + List loadedEdgesType1 = new ArrayList<>(); + TextPageLink pageLink = new TextPageLink(15); + TextPageData pageData = null; + do { + pageData = edgeService.findEdgesByTenantIdAndType(tenantId, type1, pageLink); + loadedEdgesType1.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageData.getNextPageLink(); + } + } while (pageData.hasNext()); + + Collections.sort(edgesType1, idComparator); + Collections.sort(loadedEdgesType1, idComparator); + + Assert.assertEquals(edgesType1, loadedEdgesType1); + + List loadedEdgesType2 = new ArrayList<>(); + pageLink = new TextPageLink(4); + do { + pageData = edgeService.findEdgesByTenantIdAndType(tenantId, type2, pageLink); + loadedEdgesType2.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageData.getNextPageLink(); + } + } while (pageData.hasNext()); + + Collections.sort(edgesType2, idComparator); + Collections.sort(loadedEdgesType2, idComparator); + + Assert.assertEquals(edgesType2, loadedEdgesType2); + + for (Edge edge : loadedEdgesType1) { + edgeService.deleteEdge(tenantId, edge.getId()); + } + + pageLink = new TextPageLink(4); + pageData = edgeService.findEdgesByTenantIdAndType(tenantId, type1, pageLink); + Assert.assertFalse(pageData.hasNext()); + Assert.assertEquals(0, pageData.getData().size()); + + for (Edge edge : loadedEdgesType2) { + edgeService.deleteEdge(tenantId, edge.getId()); + } + + pageLink = new TextPageLink(4); + pageData = edgeService.findEdgesByTenantIdAndType(tenantId, type2, pageLink); + Assert.assertFalse(pageData.hasNext()); + Assert.assertEquals(0, pageData.getData().size()); + } + + @Test + public void testFindEdgesByTenantIdAndCustomerId() { + Tenant tenant = new Tenant(); + tenant.setTitle("Test tenant"); + tenant = tenantService.saveTenant(tenant); + + TenantId tenantId = tenant.getId(); + + Customer customer = new Customer(); + customer.setTitle("Test customer"); + customer.setTenantId(tenantId); + customer = customerService.saveCustomer(customer); + CustomerId customerId = customer.getId(); + + List edges = new ArrayList<>(); + for (int i = 0; i < 278; i++) { + Edge edge = new Edge(); + edge.setTenantId(tenantId); + edge.setName("Edge" + i); + edge.setType("default"); + edge = edgeService.saveEdge(edge); + edges.add(edgeService.assignEdgeToCustomer(tenantId, edge.getId(), customerId)); + } + + List loadedEdges = new ArrayList<>(); + TextPageLink pageLink = new TextPageLink(23); + TextPageData pageData = null; + do { + pageData = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink); + loadedEdges.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageData.getNextPageLink(); + } + } while (pageData.hasNext()); + + Collections.sort(edges, idComparator); + Collections.sort(loadedEdges, idComparator); + + Assert.assertEquals(edges, loadedEdges); + + edgeService.unassignCustomerEdges(tenantId, customerId); + + pageLink = new TextPageLink(33); + pageData = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink); + Assert.assertFalse(pageData.hasNext()); + Assert.assertTrue(pageData.getData().isEmpty()); + + tenantService.deleteTenant(tenantId); + } + + @Test + public void testFindEdgesByTenantIdCustomerIdAndName() { + + Customer customer = new Customer(); + customer.setTitle("Test customer"); + customer.setTenantId(tenantId); + customer = customerService.saveCustomer(customer); + CustomerId customerId = customer.getId(); + + String title1 = "Edge title 1"; + List edgesTitle1 = new ArrayList<>(); + for (int i = 0; i < 175; i++) { + Edge edge = new Edge(); + edge.setTenantId(tenantId); + String suffix = RandomStringUtils.randomAlphanumeric(15); + String name = title1 + suffix; + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); + edge.setName(name); + edge.setType("default"); + edge = edgeService.saveEdge(edge); + edgesTitle1.add(edgeService.assignEdgeToCustomer(tenantId, edge.getId(), customerId)); + } + String title2 = "Edge title 2"; + List edgesTitle2 = new ArrayList<>(); + for (int i = 0; i < 143; i++) { + Edge edge = new Edge(); + edge.setTenantId(tenantId); + String suffix = RandomStringUtils.randomAlphanumeric(15); + String name = title2 + suffix; + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); + edge.setName(name); + edge.setType("default"); + edge = edgeService.saveEdge(edge); + edgesTitle2.add(edgeService.assignEdgeToCustomer(tenantId, edge.getId(), customerId)); + } + + List loadedEdgesTitle1 = new ArrayList<>(); + TextPageLink pageLink = new TextPageLink(15, title1); + TextPageData pageData = null; + do { + pageData = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink); + loadedEdgesTitle1.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageData.getNextPageLink(); + } + } while (pageData.hasNext()); + + Collections.sort(edgesTitle1, idComparator); + Collections.sort(loadedEdgesTitle1, idComparator); + + Assert.assertEquals(edgesTitle1, loadedEdgesTitle1); + + List loadedEdgesTitle2 = new ArrayList<>(); + pageLink = new TextPageLink(4, title2); + do { + pageData = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink); + loadedEdgesTitle2.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageData.getNextPageLink(); + } + } while (pageData.hasNext()); + + Collections.sort(edgesTitle2, idComparator); + Collections.sort(loadedEdgesTitle2, idComparator); + + Assert.assertEquals(edgesTitle2, loadedEdgesTitle2); + + for (Edge edge : loadedEdgesTitle1) { + edgeService.deleteEdge(tenantId, edge.getId()); + } + + pageLink = new TextPageLink(4, title1); + pageData = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink); + Assert.assertFalse(pageData.hasNext()); + Assert.assertEquals(0, pageData.getData().size()); + + for (Edge edge : loadedEdgesTitle2) { + edgeService.deleteEdge(tenantId, edge.getId()); + } + + pageLink = new TextPageLink(4, title2); + pageData = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink); + Assert.assertFalse(pageData.hasNext()); + Assert.assertEquals(0, pageData.getData().size()); + customerService.deleteCustomer(tenantId, customerId); + } + + @Test + public void testFindEdgesByTenantIdCustomerIdAndType() { + + Customer customer = new Customer(); + customer.setTitle("Test customer"); + customer.setTenantId(tenantId); + customer = customerService.saveCustomer(customer); + CustomerId customerId = customer.getId(); + + String title1 = "Edge title 1"; + String type1 = "typeC"; + List edgesType1 = new ArrayList<>(); + for (int i = 0; i < 175; i++) { + Edge edge = new Edge(); + edge.setTenantId(tenantId); + String suffix = RandomStringUtils.randomAlphanumeric(15); + String name = title1 + suffix; + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); + edge.setName(name); + edge.setType(type1); + edge = edgeService.saveEdge(edge); + edgesType1.add(edgeService.assignEdgeToCustomer(tenantId, edge.getId(), customerId)); + } + String title2 = "Edge title 2"; + String type2 = "typeD"; + List edgesType2 = new ArrayList<>(); + for (int i = 0; i < 143; i++) { + Edge edge = new Edge(); + edge.setTenantId(tenantId); + String suffix = RandomStringUtils.randomAlphanumeric(15); + String name = title2 + suffix; + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); + edge.setName(name); + edge.setType(type2); + edge = edgeService.saveEdge(edge); + edgesType2.add(edgeService.assignEdgeToCustomer(tenantId, edge.getId(), customerId)); + } + + List loadedEdgesType1 = new ArrayList<>(); + TextPageLink pageLink = new TextPageLink(15); + TextPageData pageData = null; + do { + pageData = edgeService.findEdgesByTenantIdAndCustomerIdAndType(tenantId, customerId, type1, pageLink); + loadedEdgesType1.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageData.getNextPageLink(); + } + } while (pageData.hasNext()); + + Collections.sort(edgesType1, idComparator); + Collections.sort(loadedEdgesType1, idComparator); + + Assert.assertEquals(edgesType1, loadedEdgesType1); + + List loadedEdgesType2 = new ArrayList<>(); + pageLink = new TextPageLink(4); + do { + pageData = edgeService.findEdgesByTenantIdAndCustomerIdAndType(tenantId, customerId, type2, pageLink); + loadedEdgesType2.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageData.getNextPageLink(); + } + } while (pageData.hasNext()); + + Collections.sort(edgesType2, idComparator); + Collections.sort(loadedEdgesType2, idComparator); + + Assert.assertEquals(edgesType2, loadedEdgesType2); + + for (Edge edge : loadedEdgesType1) { + edgeService.deleteEdge(tenantId, edge.getId()); + } + + pageLink = new TextPageLink(4); + pageData = edgeService.findEdgesByTenantIdAndCustomerIdAndType(tenantId, customerId, type1, pageLink); + Assert.assertFalse(pageData.hasNext()); + Assert.assertEquals(0, pageData.getData().size()); + + for (Edge edge : loadedEdgesType2) { + edgeService.deleteEdge(tenantId, edge.getId()); + } + + pageLink = new TextPageLink(4); + pageData = edgeService.findEdgesByTenantIdAndCustomerIdAndType(tenantId, customerId, type2, pageLink); + Assert.assertFalse(pageData.hasNext()); + Assert.assertEquals(0, pageData.getData().size()); + customerService.deleteCustomer(tenantId, customerId); + } + +} diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/nosql/EdgeServiceNoSqlTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/nosql/EdgeServiceNoSqlTest.java new file mode 100644 index 0000000000..5f949ecbdf --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/service/nosql/EdgeServiceNoSqlTest.java @@ -0,0 +1,23 @@ +/** + * Copyright © 2016-2019 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.service.nosql; + +import org.thingsboard.server.dao.service.BaseEdgeServiceTest; +import org.thingsboard.server.dao.service.DaoNoSqlTest; + +@DaoNoSqlTest +public class EdgeServiceNoSqlTest extends BaseEdgeServiceTest { +} diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/sql/EdgeServiceSqlTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/sql/EdgeServiceSqlTest.java new file mode 100644 index 0000000000..abe0ed4ace --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/service/sql/EdgeServiceSqlTest.java @@ -0,0 +1,23 @@ +/** + * Copyright © 2016-2019 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.service.sql; + +import org.thingsboard.server.dao.service.BaseEdgeServiceTest; +import org.thingsboard.server.dao.service.DaoSqlTest; + +@DaoSqlTest +public class EdgeServiceSqlTest extends BaseEdgeServiceTest { +} diff --git a/dao/src/test/resources/application-test.properties b/dao/src/test/resources/application-test.properties index 263da99a4b..da3049e48c 100644 --- a/dao/src/test/resources/application-test.properties +++ b/dao/src/test/resources/application-test.properties @@ -30,6 +30,9 @@ caffeine.specs.entityViews.maxSize=100000 caffeine.specs.claimDevices.timeToLiveInMinutes=1440 caffeine.specs.claimDevices.maxSize=100000 +caffeine.specs.edges.timeToLiveInMinutes=1440 +caffeine.specs.edges.maxSize=100000 + redis.connection.host=localhost redis.connection.port=6379 redis.connection.db=0