Browse Source

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

pull/2818/head
Volodymyr Babak 7 years ago
parent
commit
39591675f9
  1. 226
      application/src/main/java/org/thingsboard/server/controller/EdgeController.java
  2. 30
      application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java
  3. 1
      application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java
  4. 3
      application/src/main/resources/thingsboard.yml
  5. 627
      application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java
  6. 44
      common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java
  7. 1
      common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java
  8. 2
      common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java
  9. 43
      common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeSearchQuery.java
  10. 5
      dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java
  11. 234
      dao/src/main/java/org/thingsboard/server/dao/edge/BaseEdgeService.java
  12. 56
      dao/src/main/java/org/thingsboard/server/dao/edge/CassandraEdgeDao.java
  13. 73
      dao/src/main/java/org/thingsboard/server/dao/edge/EdgeDao.java
  14. 1
      dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
  15. 6
      dao/src/main/java/org/thingsboard/server/dao/model/nosql/EdgeEntity.java
  16. 9
      dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEntity.java
  17. 55
      dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeRepository.java
  18. 84
      dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java
  19. 5
      dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java
  20. 1
      dao/src/main/resources/sql/schema-entities.sql
  21. 4
      dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java
  22. 636
      dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java
  23. 23
      dao/src/test/java/org/thingsboard/server/dao/service/nosql/EdgeServiceNoSqlTest.java
  24. 23
      dao/src/test/java/org/thingsboard/server/dao/service/sql/EdgeServiceSqlTest.java
  25. 3
      dao/src/test/resources/application-test.properties

226
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<Edge> 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<Edge> 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<Edge> 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<Edge> 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<EdgeId> edgeIds = new ArrayList<>();
for (String strEdgeId : strEdgeIds) {
edgeIds.add(new EdgeId(toUUID(strEdgeId)));
}
List<Edge> edges = checkNotNull(edgeService.findEdgesByIdsAsync(tenantId, edgeIds).get());
return filterEdgesByReadPermission(edges);
ListenableFuture<List<Edge>> 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<Edge> filterEdgesByReadPermission(List<Edge> 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<Edge> findByQuery(@RequestBody EdgeSearchQuery query) throws ThingsboardException {
checkNotNull(query);
checkNotNull(query.getParameters());
checkNotNull(query.getEdgeTypes());
checkEntityId(query.getParameters().getEntityId(), Operation.READ);
try {
List<Edge> 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<EntitySubtype> getEdgeTypes() throws ThingsboardException {
try {
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
ListenableFuture<List<EntitySubtype>> edgeTypes = edgeService.findEdgeTypesByTenantId(tenantId);
return checkNotNull(edgeTypes.get());
} catch (Exception e) {
throw handleException(e);
}
}
}

30
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<ValidationResult> callback) {
if (currentUser.isSystemAdmin()) {
callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
} else {
ListenableFuture<Edge> 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 <T, V> FutureCallback<T> getCallback(FutureCallback<ValidationResult> callback, Function<T, ValidationResult<V>> transformer) {
return new FutureCallback<T>() {
@Override

1
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 =

3
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

627
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<Edge> idComparator;
private IdComparator<Edge> 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<Edge> 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<EntitySubtype> edgeTypes = doGetTyped("/api/edge/types",
new TypeReference<List<EntitySubtype>>() {
});
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<Edge> 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<Edge> loadedEdges = loadListOf(new TextPageLink(23), "/api/edges?");
List<Edge> loadedEdges = new ArrayList<>();
TextPageLink pageLink = new TextPageLink(23);
TextPageData<Edge> pageData = null;
do {
pageData = doGetTypedWithPageLink("/api/tenant/edges?",
new TypeReference<TextPageData<Edge>>() {
}, 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<Edge> namesOfEdge1 = fillListOf(143, name1);
List<Edge> loadedNamesOfEdge1 = loadListOf(new TextPageLink(15, name1), "/api/edges?");
Collections.sort(namesOfEdge1, idComparator);
Collections.sort(loadedNamesOfEdge1, idComparator);
assertEquals(namesOfEdge1, loadedNamesOfEdge1);
String name2 = "Entity edge2";
List<Edge> namesOfEdge2 = fillListOf(75, name2);
List<Edge> 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<Edge> pageData = doGetTypedWithPageLink("/api/edges?",
public void testFindTenantEdgesByName() throws Exception {
String title1 = "Edge title 1";
List<Edge> 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<Edge> 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<Edge> loadedEdgesTitle1 = new ArrayList<>();
TextPageLink pageLink = new TextPageLink(15, title1);
TextPageData<Edge> pageData = null;
do {
pageData = doGetTypedWithPageLink("/api/tenant/edges?",
new TypeReference<TextPageData<Edge>>() {
}, 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<Edge> loadedEdgesTitle2 = new ArrayList<>();
pageLink = new TextPageLink(4, title2);
do {
pageData = doGetTypedWithPageLink("/api/tenant/edges?",
new TypeReference<TextPageData<Edge>>() {
}, 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<TextPageData<Edge>>() {
}, 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<TextPageData<Edge>>() {
}, new TextPageLink(4, name2));
pageLink = new TextPageLink(4, title2);
pageData = doGetTypedWithPageLink("/api/tenant/edges?",
new TypeReference<TextPageData<Edge>>() {
}, 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<Edge> 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<Edge> 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<Edge> loadedEdgesType1 = new ArrayList<>();
TextPageLink pageLink = new TextPageLink(15);
TextPageData<Edge> pageData = null;
do {
pageData = doGetTypedWithPageLink("/api/tenant/edges?type={type}&",
new TypeReference<TextPageData<Edge>>() {
}, 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<Edge> loadedEdgesType2 = new ArrayList<>();
pageLink = new TextPageLink(4);
do {
pageData = doGetTypedWithPageLink("/api/tenant/edges?type={type}&",
new TypeReference<TextPageData<Edge>>() {
}, 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<TextPageData<Edge>>() {
}, 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<TextPageData<Edge>>() {
}, 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<Edge> 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<Edge> loadedEdges = new ArrayList<>();
TextPageLink pageLink = new TextPageLink(23);
TextPageData<Edge> pageData = null;
do {
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?",
new TypeReference<TextPageData<Edge>>() {
}, 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<Edge> fillListOf(int limit, String partOfName) throws Exception {
List<Edge> 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<Edge> 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<Edge> 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<Edge> loadedEdgesTitle1 = new ArrayList<>();
TextPageLink pageLink = new TextPageLink(15, title1);
TextPageData<Edge> pageData = null;
do {
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?",
new TypeReference<TextPageData<Edge>>() {
}, 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<Edge> loadedEdgesTitle2 = new ArrayList<>();
pageLink = new TextPageLink(4, title2);
do {
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?",
new TypeReference<TextPageData<Edge>>() {
}, 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<TextPageData<Edge>>() {
}, 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<TextPageData<Edge>>() {
}, pageLink);
Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size());
}
private List<Edge> loadListOf(TextPageLink pageLink, String urlTemplate) throws Exception {
List<Edge> loadedItems = new ArrayList<>();
TextPageData<Edge> 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<Edge> 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<Edge> 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<Edge> loadedEdgesType1 = new ArrayList<>();
TextPageLink pageLink = new TextPageLink(15);
TextPageData<Edge> pageData = null;
do {
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?type={type}&",
new TypeReference<TextPageData<Edge>>() {
}, 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<Edge> loadedEdgesType2 = new ArrayList<>();
pageLink = new TextPageLink(4);
do {
pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference<TextPageData<Edge>>() {
}, pageLink);
loadedItems.addAll(pageData.getData());
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?type={type}&",
new TypeReference<TextPageData<Edge>>() {
}, 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<TextPageData<Edge>>() {
}, 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<TextPageData<Edge>>() {
}, pageLink, type2);
Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size());
}
}

44
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<Edge> findEdgeByIdAsync(TenantId tenantId, EdgeId edgeId);
ListenableFuture<List<Edge>> findEdgesByIdsAsync(TenantId tenantId, List<EdgeId> edgeIds);
Edge findEdgeByTenantIdAndName(TenantId tenantId, String name);
List<Edge> findAllEdges(TenantId tenantId);
Edge saveEdge(Edge edge);
TextPageData<Edge> 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<Edge> findEdgesByTenantId(TenantId tenantId, TextPageLink pageLink);
TextPageData<Edge> findEdgesByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink);
ListenableFuture<List<Edge>> findEdgesByTenantIdAndIdsAsync(TenantId tenantId, List<EdgeId> edgeIds);
void deleteEdgesByTenantId(TenantId tenantId);
TextPageData<Edge> findEdgesByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink);
TextPageData<Edge> findEdgesByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, TextPageLink pageLink);
ListenableFuture<List<Edge>> findEdgesByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<EdgeId> edgeIds);
void unassignCustomerEdges(TenantId tenantId, CustomerId customerId);
ListenableFuture<List<Edge>> findEdgesByQuery(TenantId tenantId, EdgeSearchQuery query);
ListenableFuture<List<EntitySubtype>> findEdgeTypesByTenantId(TenantId tenantId);
}

1
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";
}

2
common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java

@ -39,6 +39,7 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> 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<EdgeId> 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();

43
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<String> 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;
}
}

5
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());

234
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<Edge> 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<List<Edge>> findEdgesByIdsAsync(TenantId tenantId, List<EdgeId> 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<Edge> edgeOpt = edgeDao.findEdgeByTenantIdAndName(tenantId.getId(), name);
return edgeOpt.orElse(null);
}
@CacheEvict(cacheNames = EDGE_CACHE, key = "{#edge.tenantId, #edge.name}")
@Override
public List<Edge> 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<Edge> 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<Edge> 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<Object> 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<Edge> 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<Edge> edges = edgeDao.findEdgesByTenantId(tenantId.getId(), pageLink);
return new TextPageData<>(edges, pageLink);
}
@Override
public TextPageData<Edge> 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<Edge> edges = edgeDao.findEdgesByTenantIdAndType(tenantId.getId(), type, pageLink);
return new TextPageData<>(edges, pageLink);
}
@Override
public ListenableFuture<List<Edge>> findEdgesByTenantIdAndIdsAsync(TenantId tenantId, List<EdgeId> 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<Edge> 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<Edge> edges = edgeDao.findEdgesByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink);
return new TextPageData<>(edges, pageLink);
}
@Override
public TextPageData<Edge> 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<Edge> edges = edgeDao.findEdgesByTenantIdAndCustomerIdAndType(tenantId.getId(), customerId.getId(), type, pageLink);
return new TextPageData<>(edges, pageLink);
}
@Override
public ListenableFuture<List<Edge>> findEdgesByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<EdgeId> 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<List<Edge>> findEdgesByQuery(TenantId tenantId, EdgeSearchQuery query) {
ListenableFuture<List<EntityRelation>> relations = relationService.findByQuery(tenantId, query.toEntitySearchQuery());
ListenableFuture<List<Edge>> edges = Futures.transformAsync(relations, r -> {
EntitySearchDirection direction = query.toEntitySearchQuery().getParameters().getDirection();
List<ListenableFuture<Edge>> 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<Edge>, List<Edge>>() {
@Nullable
@Override
public List<Edge> apply(@Nullable List<Edge> edgeList) {
return edgeList == null ? Collections.emptyList() : edgeList.stream().filter(edge -> query.getEdgeTypes().contains(edge.getType())).collect(Collectors.toList());
}
});
return edges;
}
@Override
public ListenableFuture<List<EntitySubtype>> findEdgeTypesByTenantId(TenantId tenantId) {
log.trace("Executing findEdgeTypesByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
ListenableFuture<List<EntitySubtype>> tenantEdgeTypes = edgeDao.findTenantEdgeTypesAsync(tenantId.getId());
return Futures.transform(tenantEdgeTypes,
edgeTypes -> {
edgeTypes.sort(Comparator.comparing(EntitySubtype::getType));
return edgeTypes;
});
}
private DataValidator<Edge> edgeValidator =
new DataValidator<Edge>() {
@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<Edge> 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<CustomerId, Edge> customerEdgeUnasigner = new PaginatedRemover<CustomerId, Edge>() {
@Override
protected List<Edge> 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()));
}
};
}

56
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<EdgeEntity,
return EDGE_COLUMN_FAMILY_NAME;
}
@Override
public List<Edge> findByTenantIdAndPageLink(UUID tenantId, TextPageLink pageLink) {
log.debug("Try to find edges by tenantId [{}] and pageLink [{}]", tenantId, pageLink);
List<EdgeEntity> 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<Edge> 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<Edge> findEdgesByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink) {
return null;
}
@Override
public ListenableFuture<List<Edge>> findEdgesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> 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<Edge> findEdgesByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) {
return null;
}
@Override
public List<Edge> findEdgesByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink) {
return null;
}
@Override
public ListenableFuture<List<Edge>> findEdgesByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> edgeIds) {
return null;
}
@Override
public Optional<Edge> findEdgeByTenantIdAndName(UUID tenantId, String name) {
return Optional.empty();
}
@Override
public ListenableFuture<List<EntitySubtype>> findTenantEdgeTypesAsync(UUID tenantId) {
return null;
}
}

73
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<Edge> {
/**
* 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<Edge> {
* @param pageLink the page link
* @return the list of edge objects
*/
List<Edge> findByTenantIdAndPageLink(UUID tenantId, TextPageLink pageLink);
List<Edge> 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<Edge> 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<Edge> {
*/
ListenableFuture<List<Edge>> findEdgesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> 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<Edge> 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<Edge> 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<List<Edge>> findEdgesByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> edgeIds);
/**
* Find edges by tenantId and edge name.
*
* @param tenantId the tenantId
* @param name the edge name
* @return the optional edge object
*/
Optional<Edge> findEdgeByTenantIdAndName(UUID tenantId, String name);
/**
* Find tenants edge types.
*
* @return the list of tenant edge type objects
*/
ListenableFuture<List<EntitySubtype>> findTenantEdgeTypesAsync(UUID tenantId);
}

1
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;

6
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<Edge> {
@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<Edge> {
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<Edge> {
if (customerId != null) {
edge.setCustomerId(new CustomerId(customerId));
}
edge.setType(type);
edge.setName(name);
edge.setConfiguration(configuration);
edge.setAdditionalInfo(additionalInfo);

9
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<Edge> 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<Edge> 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<Edge> implements SearchTextEntity<
if (customerId != null) {
edge.setCustomerId(new CustomerId(UUIDConverter.fromString(customerId)));
}
edge.setType(type);
edge.setName(name);
edge.setConfiguration(configuration);
edge.setAdditionalInfo(additionalInfo);

55
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<EdgeEntity, String> {
@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<EdgeEntity> 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<EdgeEntity> 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<EdgeEntity> 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<EdgeEntity> 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<EdgeEntity> 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<String> findTenantEdgeTypes(@Param("tenantId") String tenantId);
EdgeEntity findByTenantIdAndName(String tenantId, String name);
List<EdgeEntity> findEdgesByTenantIdAndCustomerIdAndIdIn(String tenantId, String customerId, List<String> edgeIds);
List<EdgeEntity> findEdgesByTenantIdAndIdIn(String tenantId, List<String> edgeIds);

84
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<EdgeEntity, Edge> imple
private EdgeRepository edgeRepository;
@Override
public List<Edge> findByTenantIdAndPageLink(UUID tenantId, TextPageLink pageLink) {
return DaoUtil.convertDataList(edgeRepository
.findByTenantIdAndPageLink(
protected Class<EdgeEntity> getEntityClass() {
return EdgeEntity.class;
}
@Override
protected CrudRepository<EdgeEntity, String> getCrudRepository() {
return edgeRepository;
}
@Override
public List<Edge> 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<EdgeEntity, Edge> imple
}
@Override
protected Class<EdgeEntity> getEntityClass() {
return EdgeEntity.class;
public List<Edge> 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<EdgeEntity, String> getCrudRepository() {
return edgeRepository;
public ListenableFuture<List<Edge>> findEdgesByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> edgeIds) {
return service.submit(() -> DaoUtil.convertDataList(
edgeRepository.findEdgesByTenantIdAndCustomerIdAndIdIn(fromTimeUUID(tenantId), fromTimeUUID(customerId), fromTimeUUIDs(edgeIds))));
}
@Override
public Optional<Edge> findEdgeByTenantIdAndName(UUID tenantId, String name) {
Edge edge = DaoUtil.getData(edgeRepository.findByTenantIdAndName(fromTimeUUID(tenantId), name));
return Optional.ofNullable(edge);
}
@Override
public List<Edge> 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<Edge> 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<List<EntitySubtype>> findTenantEdgeTypesAsync(UUID tenantId) {
return service.submit(() -> convertTenantEdgeTypesToDto(tenantId, edgeRepository.findTenantEdgeTypes(fromTimeUUID(tenantId))));
}
private List<EntitySubtype> convertTenantEdgeTypesToDto(UUID tenantId, List<String> types) {
List<EntitySubtype> 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;
}
}

5
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());

1
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)

4
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;

636
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<Edge> 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<Edge> 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<EntitySubtype> 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<Edge> 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<Edge> loadedEdges = new ArrayList<>();
TextPageLink pageLink = new TextPageLink(23);
TextPageData<Edge> 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<Edge> 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<Edge> 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<Edge> loadedEdgesTitle1 = new ArrayList<>();
TextPageLink pageLink = new TextPageLink(15, title1);
TextPageData<Edge> 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<Edge> 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<Edge> 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<Edge> 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<Edge> loadedEdgesType1 = new ArrayList<>();
TextPageLink pageLink = new TextPageLink(15);
TextPageData<Edge> 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<Edge> 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<Edge> 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<Edge> loadedEdges = new ArrayList<>();
TextPageLink pageLink = new TextPageLink(23);
TextPageData<Edge> 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<Edge> 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<Edge> 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<Edge> loadedEdgesTitle1 = new ArrayList<>();
TextPageLink pageLink = new TextPageLink(15, title1);
TextPageData<Edge> 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<Edge> 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<Edge> 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<Edge> 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<Edge> loadedEdgesType1 = new ArrayList<>();
TextPageLink pageLink = new TextPageLink(15);
TextPageData<Edge> 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<Edge> 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);
}
}

23
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 {
}

23
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 {
}

3
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

Loading…
Cancel
Save