Commit 134148c49f0cabfc269e66ce72c931405dd81e0d

Authored by Volodymyr Babak
1 parent 8416c206

Removed edgeId. Code clean up and refactoring

Showing 50 changed files with 499 additions and 688 deletions
... ... @@ -40,6 +40,8 @@ import org.thingsboard.server.common.data.id.EdgeId;
40 40 import org.thingsboard.server.common.data.id.TenantId;
41 41 import org.thingsboard.server.common.data.page.TextPageData;
42 42 import org.thingsboard.server.common.data.page.TextPageLink;
  43 +import org.thingsboard.server.common.data.page.TimePageData;
  44 +import org.thingsboard.server.common.data.page.TimePageLink;
43 45 import org.thingsboard.server.dao.exception.IncorrectParameterException;
44 46 import org.thingsboard.server.dao.model.ModelConstants;
45 47 import org.thingsboard.server.queue.util.TbCoreComponent;
... ... @@ -51,6 +53,8 @@ import java.util.ArrayList;
51 53 import java.util.List;
52 54 import java.util.stream.Collectors;
53 55
  56 +import static org.thingsboard.server.controller.EdgeController.EDGE_ID;
  57 +
54 58 @RestController
55 59 @TbCoreComponent
56 60 @RequestMapping("/api")
... ... @@ -336,9 +340,9 @@ public class AssetController extends BaseController {
336 340 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
337 341 @RequestMapping(value = "/edge/{edgeId}/asset/{assetId}", method = RequestMethod.POST)
338 342 @ResponseBody
339   - public Asset assignAssetToEdge(@PathVariable("edgeId") String strEdgeId,
  343 + public Asset assignAssetToEdge(@PathVariable(EDGE_ID) String strEdgeId,
340 344 @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
341   - checkParameter("edgeId", strEdgeId);
  345 + checkParameter(EDGE_ID, strEdgeId);
342 346 checkParameter(ASSET_ID, strAssetId);
343 347 try {
344 348 EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
... ... @@ -365,20 +369,20 @@ public class AssetController extends BaseController {
365 369 }
366 370
367 371 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
368   - @RequestMapping(value = "/edge/asset/{assetId}", method = RequestMethod.DELETE)
  372 + @RequestMapping(value = "/edge/{edgeId}/asset/{assetId}", method = RequestMethod.DELETE)
369 373 @ResponseBody
370   - public Asset unassignAssetFromEdge(@PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
  374 + public Asset unassignAssetFromEdge(@PathVariable(EDGE_ID) String strEdgeId,
  375 + @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
  376 + checkParameter(EDGE_ID, strEdgeId);
371 377 checkParameter(ASSET_ID, strAssetId);
372 378 try {
  379 + EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
  380 + Edge edge = checkEdgeId(edgeId, Operation.READ);
  381 +
373 382 AssetId assetId = new AssetId(toUUID(strAssetId));
374 383 Asset asset = checkAssetId(assetId, Operation.UNASSIGN_FROM_EDGE);
375   - if (asset.getEdgeId() == null || asset.getEdgeId().getId().equals(ModelConstants.NULL_UUID)) {
376   - throw new IncorrectParameterException("Asset isn't assigned to any edge!");
377   - }
378 384
379   - Edge edge = checkEdgeId(asset.getEdgeId(), Operation.READ);
380   -
381   - Asset savedAsset = checkNotNull(assetService.unassignAssetFromEdge(getTenantId(), assetId));
  385 + Asset savedAsset = checkNotNull(assetService.unassignAssetFromEdge(getTenantId(), assetId, edgeId));
382 386
383 387 logEntityAction(assetId, asset,
384 388 asset.getCustomerId(),
... ... @@ -398,24 +402,20 @@ public class AssetController extends BaseController {
398 402 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
399 403 @RequestMapping(value = "/edge/{edgeId}/assets", params = {"limit"}, method = RequestMethod.GET)
400 404 @ResponseBody
401   - public TextPageData<Asset> getEdgeAssets(
402   - @PathVariable("edgeId") String strEdgeId,
  405 + public TimePageData<Asset> getEdgeAssets(
  406 + @PathVariable(EDGE_ID) String strEdgeId,
403 407 @RequestParam int limit,
404   - @RequestParam(required = false) String type,
405   - @RequestParam(required = false) String textSearch,
406   - @RequestParam(required = false) String idOffset,
407   - @RequestParam(required = false) String textOffset) throws ThingsboardException {
408   - checkParameter("edgeId", strEdgeId);
  408 + @RequestParam(required = false) Long startTime,
  409 + @RequestParam(required = false) Long endTime,
  410 + @RequestParam(required = false, defaultValue = "false") boolean ascOrder,
  411 + @RequestParam(required = false) String offset) throws ThingsboardException {
  412 + checkParameter(EDGE_ID, strEdgeId);
409 413 try {
410 414 TenantId tenantId = getCurrentUser().getTenantId();
411 415 EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
412 416 checkEdgeId(edgeId, Operation.READ);
413   - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
414   - if (type != null && type.trim().length()>0) {
415   - return checkNotNull(assetService.findAssetsByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink));
416   - } else {
417   - return checkNotNull(assetService.findAssetsByTenantIdAndEdgeId(tenantId, edgeId, pageLink));
418   - }
  417 + TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset);
  418 + return checkNotNull(assetService.findAssetsByTenantIdAndEdgeId(tenantId, edgeId, pageLink).get());
419 419 } catch (Exception e) {
420 420 throw handleException(e);
421 421 }
... ...
... ... @@ -49,6 +49,9 @@ import org.thingsboard.server.common.data.id.EdgeId;
49 49 import org.thingsboard.server.common.data.id.TenantId;
50 50 import org.thingsboard.server.common.data.page.TextPageData;
51 51 import org.thingsboard.server.common.data.page.TextPageLink;
  52 +import org.thingsboard.server.common.data.page.TimePageData;
  53 +import org.thingsboard.server.common.data.page.TimePageLink;
  54 +import org.thingsboard.server.common.data.rule.RuleChain;
52 55 import org.thingsboard.server.common.data.security.DeviceCredentials;
53 56 import org.thingsboard.server.dao.device.claim.ClaimResponse;
54 57 import org.thingsboard.server.dao.device.claim.ClaimResult;
... ... @@ -519,19 +522,20 @@ public class DeviceController extends BaseController {
519 522 }
520 523
521 524 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
522   - @RequestMapping(value = "/edge/device/{deviceId}", method = RequestMethod.DELETE)
  525 + @RequestMapping(value = "/edge/{edgeId}/device/{deviceId}", method = RequestMethod.DELETE)
523 526 @ResponseBody
524   - public Device unassignDeviceFromEdge(@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
  527 + public Device unassignDeviceFromEdge(@PathVariable(EDGE_ID) String strEdgeId,
  528 + @PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
  529 + checkParameter(EDGE_ID, strEdgeId);
525 530 checkParameter(DEVICE_ID, strDeviceId);
526 531 try {
  532 + EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
  533 + Edge edge = checkEdgeId(edgeId, Operation.READ);
  534 +
527 535 DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
528 536 Device device = checkDeviceId(deviceId, Operation.UNASSIGN_FROM_EDGE);
529   - if (device.getEdgeId() == null || device.getEdgeId().getId().equals(ModelConstants.NULL_UUID)) {
530   - throw new IncorrectParameterException("Device isn't assigned to any edge!");
531   - }
532   - Edge edge = checkEdgeId(device.getEdgeId(), Operation.READ);
533 537
534   - Device savedDevice = checkNotNull(deviceService.unassignDeviceFromEdge(getCurrentUser().getTenantId(), deviceId));
  538 + Device savedDevice = checkNotNull(deviceService.unassignDeviceFromEdge(getCurrentUser().getTenantId(), deviceId, edgeId));
535 539
536 540 logEntityAction(deviceId, device,
537 541 device.getCustomerId(),
... ... @@ -549,24 +553,20 @@ public class DeviceController extends BaseController {
549 553 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
550 554 @RequestMapping(value = "/edge/{edgeId}/devices", params = {"limit"}, method = RequestMethod.GET)
551 555 @ResponseBody
552   - public TextPageData<Device> getEdgeDevices(
553   - @PathVariable("edgeId") String strEdgeId,
  556 + public TimePageData<Device> getEdgeDevices(
  557 + @PathVariable(EDGE_ID) String strEdgeId,
554 558 @RequestParam int limit,
555   - @RequestParam(required = false) String type,
556   - @RequestParam(required = false) String textSearch,
557   - @RequestParam(required = false) String idOffset,
558   - @RequestParam(required = false) String textOffset) throws ThingsboardException {
559   - checkParameter("edgeId", strEdgeId);
  559 + @RequestParam(required = false) Long startTime,
  560 + @RequestParam(required = false) Long endTime,
  561 + @RequestParam(required = false, defaultValue = "false") boolean ascOrder,
  562 + @RequestParam(required = false) String offset) throws ThingsboardException {
  563 + checkParameter(EDGE_ID, strEdgeId);
560 564 try {
561 565 TenantId tenantId = getCurrentUser().getTenantId();
562 566 EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
563 567 checkEdgeId(edgeId, Operation.READ);
564   - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
565   - if (type != null && type.trim().length()>0) {
566   - return checkNotNull(deviceService.findDevicesByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink));
567   - } else {
568   - return checkNotNull(deviceService.findDevicesByTenantIdAndEdgeId(tenantId, edgeId, pageLink));
569   - }
  568 + TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset);
  569 + return checkNotNull(deviceService.findDevicesByTenantIdAndEdgeId(tenantId, edgeId, pageLink).get());
570 570 } catch (Exception e) {
571 571 throw handleException(e);
572 572 }
... ...
... ... @@ -48,6 +48,8 @@ import org.thingsboard.server.common.data.id.UUIDBased;
48 48 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
49 49 import org.thingsboard.server.common.data.page.TextPageData;
50 50 import org.thingsboard.server.common.data.page.TextPageLink;
  51 +import org.thingsboard.server.common.data.page.TimePageData;
  52 +import org.thingsboard.server.common.data.page.TimePageLink;
51 53 import org.thingsboard.server.dao.exception.IncorrectParameterException;
52 54 import org.thingsboard.server.dao.model.ModelConstants;
53 55 import org.thingsboard.server.queue.util.TbCoreComponent;
... ... @@ -400,18 +402,20 @@ public class EntityViewController extends BaseController {
400 402 }
401 403
402 404 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
403   - @RequestMapping(value = "/edge/entityView/{entityViewId}", method = RequestMethod.DELETE)
  405 + @RequestMapping(value = "/edge/{edgeId}/entityView/{entityViewId}", method = RequestMethod.DELETE)
404 406 @ResponseBody
405   - public EntityView unassignEntityViewFromEdge(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException {
  407 + public EntityView unassignEntityViewFromEdge(@PathVariable(EDGE_ID) String strEdgeId,
  408 + @PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException {
  409 + checkParameter(EDGE_ID, strEdgeId);
406 410 checkParameter(ENTITY_VIEW_ID, strEntityViewId);
407 411 try {
  412 + EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
  413 + Edge edge = checkEdgeId(edgeId, Operation.READ);
  414 +
408 415 EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId));
409 416 EntityView entityView = checkEntityViewId(entityViewId, Operation.UNASSIGN_FROM_EDGE);
410   - if (entityView.getEdgeId() == null || entityView.getEdgeId().getId().equals(ModelConstants.NULL_UUID)) {
411   - throw new IncorrectParameterException("Entity View isn't assigned to any edge!");
412   - }
413   - Edge edge = checkEdgeId(entityView.getEdgeId(), Operation.READ);
414   - EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromEdge(getTenantId(), entityViewId));
  417 +
  418 + EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromEdge(getTenantId(), entityViewId, edgeId));
415 419 logEntityAction(entityViewId, entityView,
416 420 entityView.getCustomerId(),
417 421 ActionType.UNASSIGNED_FROM_EDGE, null, strEntityViewId, edge.getId().toString(), edge.getName());
... ... @@ -428,24 +432,20 @@ public class EntityViewController extends BaseController {
428 432 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
429 433 @RequestMapping(value = "/edge/{edgeId}/entityViews", params = {"limit"}, method = RequestMethod.GET)
430 434 @ResponseBody
431   - public TextPageData<EntityView> getEdgeEntityViews(
432   - @PathVariable("edgeId") String strEdgeId,
  435 + public TimePageData<EntityView> getEdgeEntityViews(
  436 + @PathVariable(EDGE_ID) String strEdgeId,
433 437 @RequestParam int limit,
434   - @RequestParam(required = false) String type,
435   - @RequestParam(required = false) String textSearch,
436   - @RequestParam(required = false) String idOffset,
437   - @RequestParam(required = false) String textOffset) throws ThingsboardException {
438   - checkParameter("edgeId", strEdgeId);
  438 + @RequestParam(required = false) Long startTime,
  439 + @RequestParam(required = false) Long endTime,
  440 + @RequestParam(required = false, defaultValue = "false") boolean ascOrder,
  441 + @RequestParam(required = false) String offset) throws ThingsboardException {
  442 + checkParameter(EDGE_ID, strEdgeId);
439 443 try {
440 444 TenantId tenantId = getCurrentUser().getTenantId();
441 445 EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
442 446 checkEdgeId(edgeId, Operation.READ);
443   - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
444   - if (type != null && type.trim().length()>0) {
445   - return checkNotNull(entityViewService.findEntityViewsByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink));
446   - } else {
447   - return checkNotNull(entityViewService.findEntityViewsByTenantIdAndEdgeId(tenantId, edgeId, pageLink));
448   - }
  447 + TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset);
  448 + return checkNotNull(entityViewService.findEntityViewsByTenantIdAndEdgeId(tenantId, edgeId, pageLink).get());
449 449 } catch (Exception e) {
450 450 throw handleException(e);
451 451 }
... ...
... ... @@ -554,7 +554,7 @@ public final class EdgeGrpcSession implements Closeable {
554 554 case ENTITY_DELETED_RPC_MESSAGE:
555 555 Device device = ctx.getDeviceService().findDeviceByTenantIdAndName(edge.getTenantId(), deviceName);
556 556 if (device != null) {
557   - ctx.getDeviceService().unassignDeviceFromEdge(edge.getTenantId(), device.getId());
  557 + ctx.getDeviceService().unassignDeviceFromEdge(edge.getTenantId(), device.getId(), edge.getId());
558 558 }
559 559 break;
560 560 }
... ...
... ... @@ -15,6 +15,7 @@
15 15 */
16 16 package org.thingsboard.server.service.edge.rpc.init;
17 17
  18 +import com.google.common.util.concurrent.Futures;
18 19 import io.grpc.stub.StreamObserver;
19 20 import lombok.extern.slf4j.Slf4j;
20 21 import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -54,6 +55,7 @@ import org.thingsboard.server.service.edge.rpc.constructor.EntityViewUpdateMsgCo
54 55 import org.thingsboard.server.service.edge.rpc.constructor.RuleChainUpdateMsgConstructor;
55 56
56 57 import java.util.UUID;
  58 +import java.util.concurrent.Future;
57 59
58 60 @Service
59 61 @Slf4j
... ... @@ -100,10 +102,10 @@ public class DefaultInitEdgeService implements InitEdgeService {
100 102
101 103 private void initDevices(Edge edge, StreamObserver<ResponseMsg> outputStream) {
102 104 try {
103   - TextPageLink pageLink = new TextPageLink(100);
104   - TextPageData<Device> pageData;
  105 + TimePageLink pageLink = new TimePageLink(100);
  106 + TimePageData<Device> pageData;
105 107 do {
106   - pageData = deviceService.findDevicesByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink);
  108 + pageData = deviceService.findDevicesByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink).get();
107 109 if (!pageData.getData().isEmpty()) {
108 110 log.trace("[{}] [{}] device(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
109 111 for (Device device : pageData.getData()) {
... ... @@ -130,10 +132,10 @@ public class DefaultInitEdgeService implements InitEdgeService {
130 132
131 133 private void initAssets(Edge edge, StreamObserver<ResponseMsg> outputStream) {
132 134 try {
133   - TextPageLink pageLink = new TextPageLink(100);
134   - TextPageData<Asset> pageData;
  135 + TimePageLink pageLink = new TimePageLink(100);
  136 + TimePageData<Asset> pageData;
135 137 do {
136   - pageData = assetService.findAssetsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink);
  138 + pageData = assetService.findAssetsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink).get();
137 139 if (!pageData.getData().isEmpty()) {
138 140 log.trace("[{}] [{}] asset(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
139 141 for (Asset asset : pageData.getData()) {
... ... @@ -160,10 +162,10 @@ public class DefaultInitEdgeService implements InitEdgeService {
160 162
161 163 private void initEntityViews(Edge edge, StreamObserver<ResponseMsg> outputStream) {
162 164 try {
163   - TextPageLink pageLink = new TextPageLink(100);
164   - TextPageData<EntityView> pageData;
  165 + TimePageLink pageLink = new TimePageLink(100);
  166 + TimePageData<EntityView> pageData;
165 167 do {
166   - pageData = entityViewService.findEntityViewsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink);
  168 + pageData = entityViewService.findEntityViewsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink).get();
167 169 if (!pageData.getData().isEmpty()) {
168 170 log.trace("[{}] [{}] entity view(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
169 171 for (EntityView entityView : pageData.getData()) {
... ...
... ... @@ -312,18 +312,6 @@ public class CassandraDatabaseUpgradeService extends AbstractCassandraDatabaseUp
312 312 loadCql(schemaUpdateFile);
313 313
314 314 try {
315   - cluster.getSession().execute("alter table asset add edge_id text");
316   - Thread.sleep(2500);
317   - } catch (InvalidQueryException e) {}
318   - try {
319   - cluster.getSession().execute("alter table device add edge_id text");
320   - Thread.sleep(2500);
321   - } catch (InvalidQueryException e) {}
322   - try {
323   - cluster.getSession().execute("alter table entity_view add edge_id text");
324   - Thread.sleep(2500);
325   - } catch (InvalidQueryException e) {}
326   - try {
327 315 cluster.getSession().execute("alter table rule_chain add type text");
328 316 Thread.sleep(2500);
329 317 } catch (InvalidQueryException e) {}
... ...
... ... @@ -239,15 +239,6 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
239 239 schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.6.0", SCHEMA_UPDATE_SQL);
240 240 loadSql(schemaUpdateFile, conn);
241 241 try {
242   - conn.createStatement().execute("ALTER TABLE asset ADD edge_id varchar(31)"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script
243   - } catch (Exception e) {}
244   - try {
245   - conn.createStatement().execute("ALTER TABLE device ADD edge_id varchar(31)"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script
246   - } catch (Exception e) {}
247   - try {
248   - conn.createStatement().execute("ALTER TABLE entity_view ADD edge_id varchar(31)"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script
249   - } catch (Exception e) {}
250   - try {
251 242 conn.createStatement().execute("ALTER TABLE rule_chain ADD type varchar(255) DEFAULT 'SYSTEM'"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script
252 243 } catch (Exception e) {}
253 244 log.info("Schema updated.");
... ...
... ... @@ -25,6 +25,8 @@ import org.thingsboard.server.common.data.id.EdgeId;
25 25 import org.thingsboard.server.common.data.id.TenantId;
26 26 import org.thingsboard.server.common.data.page.TextPageData;
27 27 import org.thingsboard.server.common.data.page.TextPageLink;
  28 +import org.thingsboard.server.common.data.page.TimePageData;
  29 +import org.thingsboard.server.common.data.page.TimePageLink;
28 30
29 31 import java.util.List;
30 32 import java.util.Optional;
... ... @@ -67,9 +69,7 @@ public interface AssetService {
67 69
68 70 Asset assignAssetToEdge(TenantId tenantId, AssetId assetId, EdgeId edgeId);
69 71
70   - Asset unassignAssetFromEdge(TenantId tenantId, AssetId assetId);
  72 + Asset unassignAssetFromEdge(TenantId tenantId, AssetId assetId, EdgeId edgeId);
71 73
72   - TextPageData<Asset> findAssetsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TextPageLink pageLink);
73   -
74   - TextPageData<Asset> findAssetsByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink);
  74 + ListenableFuture<TimePageData<Asset>> findAssetsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink);
75 75 }
... ...
... ... @@ -25,11 +25,13 @@ import org.thingsboard.server.common.data.id.EdgeId;
25 25 import org.thingsboard.server.common.data.id.TenantId;
26 26 import org.thingsboard.server.common.data.page.TextPageData;
27 27 import org.thingsboard.server.common.data.page.TextPageLink;
  28 +import org.thingsboard.server.common.data.page.TimePageData;
  29 +import org.thingsboard.server.common.data.page.TimePageLink;
28 30
29 31 import java.util.List;
30 32
31 33 public interface DeviceService {
32   -
  34 +
33 35 Device findDeviceById(TenantId tenantId, DeviceId deviceId);
34 36
35 37 ListenableFuture<Device> findDeviceByIdAsync(TenantId tenantId, DeviceId deviceId);
... ... @@ -68,10 +70,7 @@ public interface DeviceService {
68 70
69 71 Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId);
70 72
71   - Device unassignDeviceFromEdge(TenantId tenantId, DeviceId deviceId);
72   -
73   - TextPageData<Device> findDevicesByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TextPageLink pageLink);
74   -
75   - TextPageData<Device> findDevicesByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink);
  73 + Device unassignDeviceFromEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId);
76 74
  75 + ListenableFuture<TimePageData<Device>> findDevicesByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink);
77 76 }
... ...
... ... @@ -26,6 +26,8 @@ import org.thingsboard.server.common.data.id.EntityViewId;
26 26 import org.thingsboard.server.common.data.id.TenantId;
27 27 import org.thingsboard.server.common.data.page.TextPageData;
28 28 import org.thingsboard.server.common.data.page.TextPageLink;
  29 +import org.thingsboard.server.common.data.page.TimePageData;
  30 +import org.thingsboard.server.common.data.page.TimePageLink;
29 31
30 32 import java.util.List;
31 33
... ... @@ -68,11 +70,7 @@ public interface EntityViewService {
68 70
69 71 EntityView assignEntityViewToEdge(TenantId tenantId, EntityViewId entityViewId, EdgeId edgeId);
70 72
71   - EntityView unassignEntityViewFromEdge(TenantId tenantId, EntityViewId entityViewId);
72   -
73   - TextPageData<EntityView> findEntityViewsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TextPageLink pageLink);
74   -
75   - TextPageData<EntityView> findEntityViewsByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink);
76   -
  73 + EntityView unassignEntityViewFromEdge(TenantId tenantId, EntityViewId entityViewId, EdgeId edgeId);
77 74
  75 + ListenableFuture<TimePageData<EntityView>> findEntityViewsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink);
78 76 }
... ...
... ... @@ -18,7 +18,6 @@ package org.thingsboard.server.common.data;
18 18 import lombok.EqualsAndHashCode;
19 19 import org.thingsboard.server.common.data.id.CustomerId;
20 20 import org.thingsboard.server.common.data.id.DeviceId;
21   -import org.thingsboard.server.common.data.id.EdgeId;
22 21 import org.thingsboard.server.common.data.id.TenantId;
23 22
24 23 @EqualsAndHashCode(callSuper = true)
... ... @@ -28,7 +27,6 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
28 27
29 28 private TenantId tenantId;
30 29 private CustomerId customerId;
31   - private EdgeId edgeId;
32 30 private String name;
33 31 private String type;
34 32 private String label;
... ... @@ -48,7 +46,6 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
48 46 this.name = device.getName();
49 47 this.type = device.getType();
50 48 this.label = device.getLabel();
51   - this.edgeId = device.getEdgeId();
52 49 }
53 50
54 51 public TenantId getTenantId() {
... ... @@ -67,14 +64,6 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
67 64 this.customerId = customerId;
68 65 }
69 66
70   - public EdgeId getEdgeId() {
71   - return edgeId;
72   - }
73   -
74   - public void setEdgeId(EdgeId edgeId) {
75   - this.edgeId = edgeId;
76   - }
77   -
78 67 @Override
79 68 public String getName() {
80 69 return name;
... ... @@ -112,8 +101,6 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
112 101 builder.append(tenantId);
113 102 builder.append(", customerId=");
114 103 builder.append(customerId);
115   - builder.append(", edgeId=");
116   - builder.append(edgeId);
117 104 builder.append(", name=");
118 105 builder.append(name);
119 106 builder.append(", type=");
... ...
... ... @@ -19,7 +19,6 @@ import lombok.AllArgsConstructor;
19 19 import lombok.Data;
20 20 import lombok.EqualsAndHashCode;
21 21 import org.thingsboard.server.common.data.id.CustomerId;
22   -import org.thingsboard.server.common.data.id.EdgeId;
23 22 import org.thingsboard.server.common.data.id.EntityId;
24 23 import org.thingsboard.server.common.data.id.EntityViewId;
25 24 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -40,7 +39,6 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo<EntityViewId>
40 39 private EntityId entityId;
41 40 private TenantId tenantId;
42 41 private CustomerId customerId;
43   - private EdgeId edgeId;
44 42 private String name;
45 43 private String type;
46 44 private TelemetryEntityView keys;
... ...
... ... @@ -15,13 +15,10 @@
15 15 */
16 16 package org.thingsboard.server.common.data.asset;
17 17
18   -import com.fasterxml.jackson.databind.JsonNode;
19 18 import lombok.EqualsAndHashCode;
20 19 import org.thingsboard.server.common.data.*;
21 20 import org.thingsboard.server.common.data.id.AssetId;
22 21 import org.thingsboard.server.common.data.id.CustomerId;
23   -import org.thingsboard.server.common.data.id.EdgeId;
24   -import org.thingsboard.server.common.data.id.EdgeId;
25 22 import org.thingsboard.server.common.data.id.TenantId;
26 23
27 24 @EqualsAndHashCode(callSuper = true)
... ... @@ -34,7 +31,6 @@ public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements
34 31 private String name;
35 32 private String type;
36 33 private String label;
37   - private EdgeId edgeId;
38 34
39 35 public Asset() {
40 36 super();
... ... @@ -51,7 +47,6 @@ public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements
51 47 this.name = asset.getName();
52 48 this.type = asset.getType();
53 49 this.label = asset.getLabel();
54   - this.edgeId = asset.getEdgeId();
55 50 }
56 51
57 52 public TenantId getTenantId() {
... ... @@ -70,14 +65,6 @@ public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements
70 65 this.customerId = customerId;
71 66 }
72 67
73   - public EdgeId getEdgeId() {
74   - return edgeId;
75   - }
76   -
77   - public void setEdgeId(EdgeId edgeId) {
78   - this.edgeId = edgeId;
79   - }
80   -
81 68 @Override
82 69 public String getName() {
83 70 return name;
... ... @@ -115,8 +102,6 @@ public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements
115 102 builder.append(tenantId);
116 103 builder.append(", customerId=");
117 104 builder.append(customerId);
118   - builder.append(", edgeId=");
119   - builder.append(edgeId);
120 105 builder.append(", name=");
121 106 builder.append(name);
122 107 builder.append(", type=");
... ...
... ... @@ -341,16 +341,6 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
341 341 }
342 342 }
343 343
344   - private void deleteRelation(TenantId tenantId, EntityRelation alarmRelation) {
345   - log.debug("Deleting Alarm relation: {}", alarmRelation);
346   - relationService.deleteRelation(tenantId, alarmRelation);
347   - }
348   -
349   - private void createRelation(TenantId tenantId, EntityRelation alarmRelation) {
350   - log.debug("Creating Alarm relation: {}", alarmRelation);
351   - relationService.saveRelation(tenantId, alarmRelation);
352   - }
353   -
354 344 private Alarm merge(Alarm existing, Alarm alarm) {
355 345 if (alarm.getStartTs() > existing.getEndTs()) {
356 346 existing.setEndTs(alarm.getStartTs());
... ... @@ -395,7 +385,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
395 385 }
396 386 }
397 387
398   - private void createAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus status, boolean createAnyRelation) {
  388 + private void createAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus status, boolean createAnyRelation) throws ExecutionException, InterruptedException {
399 389 if (createAnyRelation) {
400 390 createRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + AlarmSearchStatus.ANY.name(), RelationTypeGroup.ALARM));
401 391 }
... ... @@ -404,13 +394,13 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
404 394 createRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getAckSearchStatus().name(), RelationTypeGroup.ALARM));
405 395 }
406 396
407   - private void deleteAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus status) {
  397 + private void deleteAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus status) throws ExecutionException, InterruptedException {
408 398 deleteRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.name(), RelationTypeGroup.ALARM));
409 399 deleteRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getClearSearchStatus().name(), RelationTypeGroup.ALARM));
410 400 deleteRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getAckSearchStatus().name(), RelationTypeGroup.ALARM));
411 401 }
412 402
413   - private void updateAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus oldStatus, AlarmStatus newStatus) {
  403 + private void updateAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus oldStatus, AlarmStatus newStatus) throws ExecutionException, InterruptedException {
414 404 deleteAlarmRelation(tenantId, entityId, alarmId, oldStatus);
415 405 createAlarmRelation(tenantId, entityId, alarmId, newStatus, false);
416 406 }
... ...
... ... @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.EntitySubtype;
20 20 import org.thingsboard.server.common.data.asset.Asset;
21 21 import org.thingsboard.server.common.data.id.TenantId;
22 22 import org.thingsboard.server.common.data.page.TextPageLink;
  23 +import org.thingsboard.server.common.data.page.TimePageLink;
23 24 import org.thingsboard.server.dao.Dao;
24 25
25 26 import java.util.List;
... ... @@ -116,23 +117,12 @@ public interface AssetDao extends Dao<Asset> {
116 117 ListenableFuture<List<EntitySubtype>> findTenantAssetTypesAsync(UUID tenantId);
117 118
118 119 /**
119   - * Find assets by tenantId, customerId and page link.
  120 + * Find assets by tenantId, edgeId and page link.
120 121 *
121 122 * @param tenantId the tenantId
122 123 * @param edgeId the edgeId
123 124 * @param pageLink the page link
124 125 * @return the list of asset objects
125 126 */
126   - List<Asset> findAssetsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink);
127   -
128   - /**
129   - * Find assets by tenantId, customerId, type and page link.
130   - *
131   - * @param tenantId the tenantId
132   - * @param edgeId the edgeId
133   - * @param type the type
134   - * @param pageLink the page link
135   - * @return the list of asset objects
136   - */
137   - List<Asset> findAssetsByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink);
  127 + ListenableFuture<List<Asset>> findAssetsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink);
138 128 }
... ...
... ... @@ -16,6 +16,7 @@
16 16 package org.thingsboard.server.dao.asset;
17 17
18 18
  19 +import com.google.common.base.Function;
19 20 import com.google.common.util.concurrent.Futures;
20 21 import com.google.common.util.concurrent.ListenableFuture;
21 22 import com.google.common.util.concurrent.MoreExecutors;
... ... @@ -29,12 +30,14 @@ import org.springframework.cache.annotation.Cacheable;
29 30 import org.springframework.stereotype.Service;
30 31 import org.springframework.util.StringUtils;
31 32 import org.thingsboard.server.common.data.Customer;
  33 +import org.thingsboard.server.common.data.Device;
32 34 import org.thingsboard.server.common.data.EntitySubtype;
33 35 import org.thingsboard.server.common.data.EntityType;
34 36 import org.thingsboard.server.common.data.EntityView;
35 37 import org.thingsboard.server.common.data.Tenant;
36 38 import org.thingsboard.server.common.data.asset.Asset;
37 39 import org.thingsboard.server.common.data.asset.AssetSearchQuery;
  40 +import org.thingsboard.server.common.data.edge.Edge;
38 41 import org.thingsboard.server.common.data.id.AssetId;
39 42 import org.thingsboard.server.common.data.id.CustomerId;
40 43 import org.thingsboard.server.common.data.id.EdgeId;
... ... @@ -42,9 +45,13 @@ import org.thingsboard.server.common.data.id.EntityId;
42 45 import org.thingsboard.server.common.data.id.TenantId;
43 46 import org.thingsboard.server.common.data.page.TextPageData;
44 47 import org.thingsboard.server.common.data.page.TextPageLink;
  48 +import org.thingsboard.server.common.data.page.TimePageData;
  49 +import org.thingsboard.server.common.data.page.TimePageLink;
45 50 import org.thingsboard.server.common.data.relation.EntityRelation;
46 51 import org.thingsboard.server.common.data.relation.EntitySearchDirection;
  52 +import org.thingsboard.server.common.data.relation.RelationTypeGroup;
47 53 import org.thingsboard.server.dao.customer.CustomerDao;
  54 +import org.thingsboard.server.dao.edge.EdgeService;
48 55 import org.thingsboard.server.dao.entity.AbstractEntityService;
49 56 import org.thingsboard.server.dao.entityview.EntityViewService;
50 57 import org.thingsboard.server.dao.exception.DataValidationException;
... ... @@ -52,6 +59,7 @@ import org.thingsboard.server.dao.service.DataValidator;
52 59 import org.thingsboard.server.dao.service.PaginatedRemover;
53 60 import org.thingsboard.server.dao.tenant.TenantDao;
54 61
  62 +import javax.annotation.Nullable;
55 63 import java.util.ArrayList;
56 64 import java.util.Collections;
57 65 import java.util.Comparator;
... ... @@ -90,6 +98,9 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
90 98 private EntityViewService entityViewService;
91 99
92 100 @Autowired
  101 + private EdgeService edgeService;
  102 +
  103 + @Autowired
93 104 private CacheManager cacheManager;
94 105
95 106 @Override
... ... @@ -285,36 +296,52 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
285 296 @Override
286 297 public Asset assignAssetToEdge(TenantId tenantId, AssetId assetId, EdgeId edgeId) {
287 298 Asset asset = findAssetById(tenantId, assetId);
288   - asset.setEdgeId(edgeId);
289   - return saveAsset(asset);
  299 + Edge edge = edgeService.findEdgeById(tenantId, edgeId);
  300 + if (edge == null) {
  301 + throw new DataValidationException("Can't assign asset to non-existent edge!");
  302 + }
  303 + if (!edge.getTenantId().getId().equals(asset.getTenantId().getId())) {
  304 + throw new DataValidationException("Can't assign asset to edge from different tenant!");
  305 + }
  306 + try {
  307 + createRelation(tenantId, new EntityRelation(edgeId, assetId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE));
  308 + } catch (ExecutionException | InterruptedException e) {
  309 + log.warn("[{}] Failed to create asset relation. Edge Id: [{}]", assetId, edgeId);
  310 + throw new RuntimeException(e);
  311 + }
  312 + return asset;
290 313 }
291 314
292 315 @Override
293   - public Asset unassignAssetFromEdge(TenantId tenantId, AssetId assetId) {
  316 + public Asset unassignAssetFromEdge(TenantId tenantId, AssetId assetId, EdgeId edgeId) {
294 317 Asset asset = findAssetById(tenantId, assetId);
295   - asset.setEdgeId(null);
296   - return saveAsset(asset);
  318 + Edge edge = edgeService.findEdgeById(tenantId, edgeId);
  319 + if (edge == null) {
  320 + throw new DataValidationException("Can't unassign asset from non-existent edge!");
  321 + }
  322 + try {
  323 + deleteRelation(tenantId, new EntityRelation(edgeId, assetId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE));
  324 + } catch (ExecutionException | InterruptedException e) {
  325 + log.warn("[{}] Failed to delete asset relation. Edge Id: [{}]", assetId, edgeId);
  326 + throw new RuntimeException(e);
  327 + }
  328 + return asset;
297 329 }
298 330
299 331 @Override
300   - public TextPageData<Asset> findAssetsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TextPageLink pageLink) {
  332 + public ListenableFuture<TimePageData<Asset>> findAssetsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink) {
301 333 log.trace("Executing findAssetsByTenantIdAndEdgeId, tenantId [{}], edgeId [{}], pageLink [{}]", tenantId, edgeId, pageLink);
302 334 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
303 335 validateId(edgeId, INCORRECT_EDGE_ID + edgeId);
304 336 validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink);
305   - List<Asset> assets = assetDao.findAssetsByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink);
306   - return new TextPageData<>(assets, pageLink);
307   - }
308   -
309   - @Override
310   - public TextPageData<Asset> findAssetsByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink) {
311   - log.trace("Executing findAssetsByTenantIdAndEdgeIdAndType, tenantId [{}], edgeId [{}], type [{}], pageLink [{}]", tenantId, edgeId, type, pageLink);
312   - validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
313   - validateId(edgeId, INCORRECT_EDGE_ID + edgeId);
314   - validateString(type, "Incorrect type " + type);
315   - validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink);
316   - List<Asset> assets = assetDao.findAssetsByTenantIdAndEdgeIdAndType(tenantId.getId(), edgeId.getId(), type, pageLink);
317   - return new TextPageData<>(assets, pageLink);
  337 + ListenableFuture<List<Asset>> assets = assetDao.findAssetsByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink);
  338 + return Futures.transform(assets, new Function<List<Asset>, TimePageData<Asset>>() {
  339 + @Nullable
  340 + @Override
  341 + public TimePageData<Asset> apply(@Nullable List<Asset> assets) {
  342 + return new TimePageData<>(assets, pageLink);
  343 + }
  344 + }, MoreExecutors.directExecutor());
318 345 }
319 346
320 347 private DataValidator<Asset> assetValidator =
... ...
... ... @@ -25,16 +25,23 @@ import com.google.common.util.concurrent.Futures;
25 25 import com.google.common.util.concurrent.ListenableFuture;
26 26 import com.google.common.util.concurrent.MoreExecutors;
27 27 import lombok.extern.slf4j.Slf4j;
  28 +import org.springframework.beans.factory.annotation.Autowired;
28 29 import org.springframework.stereotype.Component;
  30 +import org.thingsboard.server.common.data.Device;
29 31 import org.thingsboard.server.common.data.EntitySubtype;
30 32 import org.thingsboard.server.common.data.EntityType;
31 33 import org.thingsboard.server.common.data.asset.Asset;
  34 +import org.thingsboard.server.common.data.id.EdgeId;
32 35 import org.thingsboard.server.common.data.id.TenantId;
33 36 import org.thingsboard.server.common.data.page.TextPageLink;
  37 +import org.thingsboard.server.common.data.page.TimePageLink;
  38 +import org.thingsboard.server.common.data.relation.EntityRelation;
  39 +import org.thingsboard.server.common.data.relation.RelationTypeGroup;
34 40 import org.thingsboard.server.dao.DaoUtil;
35 41 import org.thingsboard.server.dao.model.EntitySubtypeEntity;
36 42 import org.thingsboard.server.dao.model.nosql.AssetEntity;
37 43 import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao;
  44 +import org.thingsboard.server.dao.relation.RelationDao;
38 45 import org.thingsboard.server.dao.util.NoSqlDao;
39 46
40 47 import javax.annotation.Nullable;
... ... @@ -68,6 +75,9 @@ import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY;
68 75 @NoSqlDao
69 76 public class CassandraAssetDao extends CassandraAbstractSearchTextDao<AssetEntity, Asset> implements AssetDao {
70 77
  78 + @Autowired
  79 + private RelationDao relationDao;
  80 +
71 81 @Override
72 82 protected Class<AssetEntity> getColumnFamilyClass() {
73 83 return AssetEntity.class;
... ... @@ -190,30 +200,16 @@ public class CassandraAssetDao extends CassandraAbstractSearchTextDao<AssetEntit
190 200 }
191 201
192 202 @Override
193   - public List<Asset> findAssetsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink) {
194   -// log.debug("Try to find assets by tenantId [{}], customerId[{}] and pageLink [{}]", tenantId, customerId, pageLink);
195   -// List<AssetEntity> assetEntities = findPageWithTextSearch(new TenantId(tenantId), ASSET_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
196   -// Arrays.asList(eq(ASSET_CUSTOMER_ID_PROPERTY, customerId),
197   -// eq(ASSET_TENANT_ID_PROPERTY, tenantId)),
198   -// pageLink);
199   -//
200   -// log.trace("Found assets [{}] by tenantId [{}], customerId [{}] and pageLink [{}]", assetEntities, tenantId, customerId, pageLink);
201   -// return DaoUtil.convertDataList(assetEntities);
202   - throw new UnsupportedOperationException("Cassandra is not supported yet");
203   - }
204   -
205   - @Override
206   - public List<Asset> findAssetsByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink) {
207   -// log.debug("Try to find assets by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", tenantId, customerId, type, pageLink);
208   -// List<AssetEntity> assetEntities = findPageWithTextSearch(new TenantId(tenantId), ASSET_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
209   -// Arrays.asList(eq(ASSET_TYPE_PROPERTY, type),
210   -// eq(ASSET_CUSTOMER_ID_PROPERTY, customerId),
211   -// eq(ASSET_TENANT_ID_PROPERTY, tenantId)),
212   -// pageLink);
213   -//
214   -// log.trace("Found assets [{}] by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", assetEntities, tenantId, customerId, type, pageLink);
215   -// return DaoUtil.convertDataList(assetEntities);
216   - throw new UnsupportedOperationException("Cassandra is not supported yet");
  203 + public ListenableFuture<List<Asset>> findAssetsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink) {
  204 + log.debug("Try to find assets by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink);
  205 + ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(new TenantId(tenantId), new EdgeId(edgeId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE, EntityType.ASSET, pageLink);
  206 + return Futures.transformAsync(relations, input -> {
  207 + List<ListenableFuture<Asset>> assetFutures = new ArrayList<>(input.size());
  208 + for (EntityRelation relation : input) {
  209 + assetFutures.add(findByIdAsync(new TenantId(tenantId), relation.getTo().getId()));
  210 + }
  211 + return Futures.successfulAsList(assetFutures);
  212 + }, MoreExecutors.directExecutor());
217 213 }
218 214
219 215 }
... ...
... ... @@ -162,16 +162,6 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
162 162 }
163 163 }
164 164
165   - private void deleteRelation(TenantId tenantId, EntityRelation dashboardRelation) throws ExecutionException, InterruptedException {
166   - log.debug("Deleting Dashboard relation: {}", dashboardRelation);
167   - relationService.deleteRelationAsync(tenantId, dashboardRelation).get();
168   - }
169   -
170   - private void createRelation(TenantId tenantId, EntityRelation dashboardRelation) throws ExecutionException, InterruptedException {
171   - log.debug("Creating Dashboard relation: {}", dashboardRelation);
172   - relationService.saveRelationAsync(tenantId, dashboardRelation).get();
173   - }
174   -
175 165 @Override
176 166 public void deleteDashboard(TenantId tenantId, DashboardId dashboardId) {
177 167 log.trace("Executing deleteDashboard [{}]", dashboardId);
... ...
... ... @@ -25,16 +25,22 @@ import com.google.common.util.concurrent.Futures;
25 25 import com.google.common.util.concurrent.ListenableFuture;
26 26 import com.google.common.util.concurrent.MoreExecutors;
27 27 import lombok.extern.slf4j.Slf4j;
  28 +import org.springframework.beans.factory.annotation.Autowired;
28 29 import org.springframework.stereotype.Component;
29 30 import org.thingsboard.server.common.data.Device;
30 31 import org.thingsboard.server.common.data.EntitySubtype;
31 32 import org.thingsboard.server.common.data.EntityType;
  33 +import org.thingsboard.server.common.data.id.EdgeId;
32 34 import org.thingsboard.server.common.data.id.TenantId;
33 35 import org.thingsboard.server.common.data.page.TextPageLink;
  36 +import org.thingsboard.server.common.data.page.TimePageLink;
  37 +import org.thingsboard.server.common.data.relation.EntityRelation;
  38 +import org.thingsboard.server.common.data.relation.RelationTypeGroup;
34 39 import org.thingsboard.server.dao.DaoUtil;
35 40 import org.thingsboard.server.dao.model.EntitySubtypeEntity;
36 41 import org.thingsboard.server.dao.model.nosql.DeviceEntity;
37 42 import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao;
  43 +import org.thingsboard.server.dao.relation.RelationDao;
38 44 import org.thingsboard.server.dao.util.NoSqlDao;
39 45
40 46 import javax.annotation.Nullable;
... ... @@ -68,6 +74,9 @@ import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY;
68 74 @NoSqlDao
69 75 public class CassandraDeviceDao extends CassandraAbstractSearchTextDao<DeviceEntity, Device> implements DeviceDao {
70 76
  77 + @Autowired
  78 + private RelationDao relationDao;
  79 +
71 80 @Override
72 81 protected Class<DeviceEntity> getColumnFamilyClass() {
73 82 return DeviceEntity.class;
... ... @@ -190,30 +199,17 @@ public class CassandraDeviceDao extends CassandraAbstractSearchTextDao<DeviceEnt
190 199 }
191 200
192 201 @Override
193   - public List<Device> findDevicesByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink) {
194   -// log.debug("Try to find devices by tenantId [{}], customerId[{}] and pageLink [{}]", tenantId, customerId, pageLink);
195   -// List<DeviceEntity> deviceEntities = findPageWithTextSearch(new TenantId(tenantId), DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
196   -// Arrays.asList(eq(DEVICE_CUSTOMER_ID_PROPERTY, customerId),
197   -// eq(DEVICE_TENANT_ID_PROPERTY, tenantId)),
198   -// pageLink);
199   -//
200   -// log.trace("Found devices [{}] by tenantId [{}], customerId [{}] and pageLink [{}]", deviceEntities, tenantId, customerId, pageLink);
201   -// return DaoUtil.convertDataList(deviceEntities);
202   - throw new UnsupportedOperationException("Cassandra is not supported yet");
  202 + public ListenableFuture<List<Device>> findDevicesByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink) {
  203 + log.debug("Try to find devices by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink);
  204 + ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(new TenantId(tenantId), new EdgeId(edgeId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE, EntityType.DEVICE, pageLink);
  205 + return Futures.transformAsync(relations, input -> {
  206 + List<ListenableFuture<Device>> deviceFutures = new ArrayList<>(input.size());
  207 + for (EntityRelation relation : input) {
  208 + deviceFutures.add(findByIdAsync(new TenantId(tenantId), relation.getTo().getId()));
  209 + }
  210 + return Futures.successfulAsList(deviceFutures);
  211 + }, MoreExecutors.directExecutor());
203 212 }
204 213
205   - @Override
206   - public List<Device> findDevicesByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink) {
207   -// log.debug("Try to find devices by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", tenantId, customerId, type, pageLink);
208   -// List<DeviceEntity> deviceEntities = findPageWithTextSearch(new TenantId(tenantId), DEVICE_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
209   -// Arrays.asList(eq(DEVICE_TYPE_PROPERTY, type),
210   -// eq(DEVICE_CUSTOMER_ID_PROPERTY, customerId),
211   -// eq(DEVICE_TENANT_ID_PROPERTY, tenantId)),
212   -// pageLink);
213   -//
214   -// log.trace("Found devices [{}] by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", deviceEntities, tenantId, customerId, type, pageLink);
215   -// return DaoUtil.convertDataList(deviceEntities);
216   - throw new UnsupportedOperationException("Cassandra is not supported yet");
217   - }
218 214
219 215 }
... ...
... ... @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.Device;
20 20 import org.thingsboard.server.common.data.EntitySubtype;
21 21 import org.thingsboard.server.common.data.id.TenantId;
22 22 import org.thingsboard.server.common.data.page.TextPageLink;
  23 +import org.thingsboard.server.common.data.page.TimePageLink;
23 24 import org.thingsboard.server.dao.Dao;
24 25
25 26 import java.util.List;
... ... @@ -124,16 +125,5 @@ public interface DeviceDao extends Dao<Device> {
124 125 * @param pageLink the page link
125 126 * @return the list of device objects
126 127 */
127   - List<Device> findDevicesByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink);
128   -
129   - /**
130   - * Find devices by tenantId, edgeId, type and page link.
131   - *
132   - * @param tenantId the tenantId
133   - * @param edgeId the edgeId
134   - * @param type the type
135   - * @param pageLink the page link
136   - * @return the list of device objects
137   - */
138   - List<Device> findDevicesByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink);
  128 + ListenableFuture<List<Device>> findDevicesByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink);
139 129 }
... ...
... ... @@ -41,19 +41,26 @@ import org.thingsboard.server.common.data.id.CustomerId;
41 41 import org.thingsboard.server.common.data.id.DeviceId;
42 42 import org.thingsboard.server.common.data.id.EdgeId;
43 43 import org.thingsboard.server.common.data.id.EntityId;
  44 +import org.thingsboard.server.common.data.id.RuleChainId;
44 45 import org.thingsboard.server.common.data.id.TenantId;
45 46 import org.thingsboard.server.common.data.page.TextPageData;
46 47 import org.thingsboard.server.common.data.page.TextPageLink;
  48 +import org.thingsboard.server.common.data.page.TimePageData;
  49 +import org.thingsboard.server.common.data.page.TimePageLink;
47 50 import org.thingsboard.server.common.data.relation.EntityRelation;
48 51 import org.thingsboard.server.common.data.relation.EntitySearchDirection;
  52 +import org.thingsboard.server.common.data.relation.RelationTypeGroup;
  53 +import org.thingsboard.server.common.data.rule.RuleChain;
49 54 import org.thingsboard.server.common.data.security.DeviceCredentials;
50 55 import org.thingsboard.server.common.data.security.DeviceCredentialsType;
51 56 import org.thingsboard.server.dao.customer.CustomerDao;
  57 +import org.thingsboard.server.dao.edge.EdgeService;
52 58 import org.thingsboard.server.dao.entity.AbstractEntityService;
53 59 import org.thingsboard.server.dao.entityview.EntityViewService;
54 60 import org.thingsboard.server.dao.exception.DataValidationException;
55 61 import org.thingsboard.server.dao.service.DataValidator;
56 62 import org.thingsboard.server.dao.service.PaginatedRemover;
  63 +import org.thingsboard.server.dao.service.Validator;
57 64 import org.thingsboard.server.dao.tenant.TenantDao;
58 65
59 66 import javax.annotation.Nullable;
... ... @@ -99,6 +106,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
99 106 private EntityViewService entityViewService;
100 107
101 108 @Autowired
  109 + private EdgeService edgeService;
  110 +
  111 + @Autowired
102 112 private CacheManager cacheManager;
103 113
104 114 @Override
... ... @@ -324,36 +334,52 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
324 334 @Override
325 335 public Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId) {
326 336 Device device = findDeviceById(tenantId, deviceId);
327   - device.setEdgeId(edgeId);
328   - return saveDevice(device);
  337 + Edge edge = edgeService.findEdgeById(tenantId, edgeId);
  338 + if (edge == null) {
  339 + throw new DataValidationException("Can't assign device to non-existent edge!");
  340 + }
  341 + if (!edge.getTenantId().getId().equals(device.getTenantId().getId())) {
  342 + throw new DataValidationException("Can't assign device to edge from different tenant!");
  343 + }
  344 + try {
  345 + createRelation(tenantId, new EntityRelation(edgeId, deviceId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE));
  346 + } catch (ExecutionException | InterruptedException e) {
  347 + log.warn("[{}] Failed to create device relation. Edge Id: [{}]", deviceId, edgeId);
  348 + throw new RuntimeException(e);
  349 + }
  350 + return device;
329 351 }
330 352
331 353 @Override
332   - public Device unassignDeviceFromEdge(TenantId tenantId, DeviceId deviceId) {
  354 + public Device unassignDeviceFromEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId) {
333 355 Device device = findDeviceById(tenantId, deviceId);
334   - device.setEdgeId(null);
335   - return saveDevice(device);
  356 + Edge edge = edgeService.findEdgeById(tenantId, edgeId);
  357 + if (edge == null) {
  358 + throw new DataValidationException("Can't unassign device from non-existent edge!");
  359 + }
  360 + try {
  361 + deleteRelation(tenantId, new EntityRelation(edgeId, deviceId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE));
  362 + } catch (ExecutionException | InterruptedException e) {
  363 + log.warn("[{}] Failed to delete device relation. Edge Id: [{}]", deviceId, edgeId);
  364 + throw new RuntimeException(e);
  365 + }
  366 + return device;
336 367 }
337 368
338 369 @Override
339   - public TextPageData<Device> findDevicesByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TextPageLink pageLink) {
  370 + public ListenableFuture<TimePageData<Device>> findDevicesByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink) {
340 371 log.trace("Executing findDevicesByTenantIdAndEdgeId, tenantId [{}], edgeId [{}], pageLink [{}]", tenantId, edgeId, pageLink);
341 372 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
342 373 validateId(edgeId, INCORRECT_EDGE_ID + edgeId);
343 374 validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink);
344   - List<Device> devices = deviceDao.findDevicesByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink);
345   - return new TextPageData<>(devices, pageLink);
346   - }
347   -
348   - @Override
349   - public TextPageData<Device> findDevicesByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink) {
350   - log.trace("Executing findDevicesByTenantIdAndEdgeIdAndType, tenantId [{}], edgeId [{}], type [{}], pageLink [{}]", tenantId, edgeId, type, pageLink);
351   - validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
352   - validateId(edgeId, INCORRECT_EDGE_ID + edgeId);
353   - validateString(type, "Incorrect type " + type);
354   - validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink);
355   - List<Device> devices = deviceDao.findDevicesByTenantIdAndEdgeIdAndType(tenantId.getId(), edgeId.getId(), type, pageLink);
356   - return new TextPageData<>(devices, pageLink);
  375 + ListenableFuture<List<Device>> devices = deviceDao.findDevicesByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink);
  376 + return Futures.transform(devices, new Function<List<Device>, TimePageData<Device>>() {
  377 + @Nullable
  378 + @Override
  379 + public TimePageData<Device> apply(@Nullable List<Device> devices) {
  380 + return new TimePageData<>(devices, pageLink);
  381 + }
  382 + }, MoreExecutors.directExecutor());
357 383 }
358 384
359 385 private DataValidator<Device> deviceValidator =
... ...
... ... @@ -62,6 +62,7 @@ import org.thingsboard.server.common.data.page.TimePageData;
62 62 import org.thingsboard.server.common.data.page.TimePageLink;
63 63 import org.thingsboard.server.common.data.relation.EntityRelation;
64 64 import org.thingsboard.server.common.data.relation.EntitySearchDirection;
  65 +import org.thingsboard.server.common.data.relation.RelationTypeGroup;
65 66 import org.thingsboard.server.common.data.rule.RuleChain;
66 67 import org.thingsboard.server.common.data.rule.RuleChainMetaData;
67 68 import org.thingsboard.server.common.data.rule.RuleChainType;
... ... @@ -75,6 +76,7 @@ import org.thingsboard.server.dao.entity.AbstractEntityService;
75 76 import org.thingsboard.server.dao.entityview.EntityViewService;
76 77 import org.thingsboard.server.dao.event.EventService;
77 78 import org.thingsboard.server.dao.exception.DataValidationException;
  79 +import org.thingsboard.server.dao.relation.RelationService;
78 80 import org.thingsboard.server.dao.rule.RuleChainService;
79 81 import org.thingsboard.server.dao.service.DataValidator;
80 82 import org.thingsboard.server.dao.service.PaginatedRemover;
... ... @@ -144,6 +146,9 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic
144 146 @Autowired
145 147 private EntityViewService entityViewService;
146 148
  149 + @Autowired
  150 + private RelationService relationService;
  151 +
147 152 private ExecutorService tsCallBackExecutor;
148 153
149 154 @PostConstruct
... ... @@ -219,7 +224,7 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic
219 224
220 225 dashboardService.unassignEdgeDashboards(tenantId, edgeId);
221 226 // TODO: validate that rule chains are removed by deleteEntityRelations(tenantId, edgeId); call
222   - ruleChainService.unassignEdgeRuleChains(tenantId, edgeId);
  227 + ruleChainService.unassignEdgeRuleChains(tenantId, edgeId);
223 228
224 229 List<Object> list = new ArrayList<>();
225 230 list.add(edge.getTenantId());
... ... @@ -385,15 +390,18 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic
385 390 }
386 391
387 392 private void processCustomTbMsg(TenantId tenantId, TbMsg tbMsg, FutureCallback<Void> callback) {
388   - EdgeId edgeId = getEdgeIdByOriginatorId(tenantId, tbMsg.getOriginator());
389   - EdgeQueueEntityType edgeQueueEntityType = getEdgeQueueTypeByEntityType(tbMsg.getOriginator().getEntityType());
390   - if (edgeId != null && edgeQueueEntityType != null) {
391   - try {
392   - saveEventToEdgeQueue(tenantId, edgeId, edgeQueueEntityType, tbMsg.getType(), Base64.encodeBase64String(TbMsg.toByteArray(tbMsg)), callback);
393   - } catch (IOException e) {
394   - log.error("Error while saving custom tbMsg into Edge Queue", e);
  393 + ListenableFuture<EdgeId> edgeIdFuture = getEdgeIdByOriginatorId(tenantId, tbMsg.getOriginator());
  394 + Futures.transform(edgeIdFuture, edgeId -> {
  395 + EdgeQueueEntityType edgeQueueEntityType = getEdgeQueueTypeByEntityType(tbMsg.getOriginator().getEntityType());
  396 + if (edgeId != null && edgeQueueEntityType != null) {
  397 + try {
  398 + saveEventToEdgeQueue(tenantId, edgeId, edgeQueueEntityType, tbMsg.getType(), Base64.encodeBase64String(TbMsg.toByteArray(tbMsg)), callback);
  399 + } catch (IOException e) {
  400 + log.error("Error while saving custom tbMsg into Edge Queue", e);
  401 + }
395 402 }
396   - }
  403 + return null;
  404 + }, MoreExecutors.directExecutor());
397 405 }
398 406
399 407 private EdgeQueueEntityType getEdgeQueueTypeByEntityType(EntityType entityType) {
... ... @@ -410,23 +418,30 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic
410 418 }
411 419 }
412 420
413   - private EdgeId getEdgeIdByOriginatorId(TenantId tenantId, EntityId originatorId) {
414   - switch (originatorId.getEntityType()) {
415   - case DEVICE:
416   - Device device = deviceService.findDeviceById(tenantId, new DeviceId(originatorId.getId()));
417   - return device.getEdgeId();
418   - case ASSET:
419   - Asset asset = assetService.findAssetById(tenantId, new AssetId(originatorId.getId()));
420   - return asset.getEdgeId();
421   - case ENTITY_VIEW:
422   - EntityView entityView = entityViewService.findEntityViewById(tenantId, new EntityViewId(originatorId.getId()));
423   - return entityView.getEdgeId();
424   - default:
425   - log.info("Unsupported entity type: [{}]", originatorId.getEntityType());
426   - return null;
  421 + private ListenableFuture<EdgeId> getEdgeIdByOriginatorId(TenantId tenantId, EntityId originatorId) {
  422 + List<EntityRelation> originatorEdgeRelations = relationService.findByToAndType(tenantId, originatorId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
  423 + if (originatorEdgeRelations != null && originatorEdgeRelations.size() > 0) {
  424 + return Futures.immediateFuture(new EdgeId(originatorEdgeRelations.get(0).getFrom().getId()));
  425 + } else {
  426 + return Futures.immediateFuture(null);
427 427 }
428 428 }
429 429
  430 + private void pushEventToEdge(TenantId tenantId, EntityId originatorId, EdgeQueueEntityType edgeQueueEntityType, TbMsg tbMsg, FutureCallback<Void> callback) {
  431 + ListenableFuture<EdgeId> edgeIdFuture = getEdgeIdByOriginatorId(tenantId, originatorId);
  432 + Futures.transform(edgeIdFuture, edgeId -> {
  433 + if (edgeId != null) {
  434 + try {
  435 + pushEventToEdge(tenantId, edgeId, edgeQueueEntityType, tbMsg, callback);
  436 + } catch (Exception e) {
  437 + log.error("Failed to push event to edge, edgeId [{}], tbMsg [{}]", edgeId, tbMsg, e);
  438 + }
  439 + }
  440 + return null;
  441 + },
  442 + MoreExecutors.directExecutor());
  443 + }
  444 +
430 445 private void processDevice(TenantId tenantId, TbMsg tbMsg, FutureCallback<Void> callback) throws IOException {
431 446 switch (tbMsg.getType()) {
432 447 case DataConstants.ENTITY_ASSIGNED_TO_EDGE:
... ... @@ -437,9 +452,7 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic
437 452 case DataConstants.ENTITY_CREATED:
438 453 case DataConstants.ENTITY_UPDATED:
439 454 Device device = mapper.readValue(tbMsg.getData(), Device.class);
440   - if (device.getEdgeId() != null) {
441   - pushEventToEdge(tenantId, device.getEdgeId(), EdgeQueueEntityType.DEVICE, tbMsg, callback);
442   - }
  455 + pushEventToEdge(tenantId, device.getId(), EdgeQueueEntityType.DEVICE, tbMsg, callback);
443 456 break;
444 457 default:
445 458 log.warn("Unsupported msgType [{}], tbMsg [{}]", tbMsg.getType(), tbMsg);
... ... @@ -471,9 +484,7 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic
471 484 case DataConstants.ENTITY_CREATED:
472 485 case DataConstants.ENTITY_UPDATED:
473 486 Asset asset = mapper.readValue(tbMsg.getData(), Asset.class);
474   - if (asset.getEdgeId() != null) {
475   - pushEventToEdge(tenantId, asset.getEdgeId(), EdgeQueueEntityType.ASSET, tbMsg, callback);
476   - }
  487 + pushEventToEdge(tenantId, asset.getId(), EdgeQueueEntityType.ASSET, tbMsg, callback);
477 488 break;
478 489 default:
479 490 log.warn("Unsupported msgType [{}], tbMsg [{}]", tbMsg.getType(), tbMsg);
... ... @@ -490,9 +501,7 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic
490 501 case DataConstants.ENTITY_CREATED:
491 502 case DataConstants.ENTITY_UPDATED:
492 503 EntityView entityView = mapper.readValue(tbMsg.getData(), EntityView.class);
493   - if (entityView.getEdgeId() != null) {
494   - pushEventToEdge(tenantId, entityView.getEdgeId(), EdgeQueueEntityType.ENTITY_VIEW, tbMsg, callback);
495   - }
  504 + pushEventToEdge(tenantId, entityView.getId(), EdgeQueueEntityType.ENTITY_VIEW, tbMsg, callback);
496 505 break;
497 506 default:
498 507 log.warn("Unsupported msgType [{}], tbMsg [{}]", tbMsg.getType(), tbMsg);
... ... @@ -507,10 +516,9 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic
507 516 case DataConstants.ALARM_ACK:
508 517 case DataConstants.ALARM_CLEAR:
509 518 Alarm alarm = mapper.readValue(tbMsg.getData(), Alarm.class);
510   - EdgeId edgeId = getEdgeIdByOriginatorId(tenantId, alarm.getOriginator());
511 519 EdgeQueueEntityType edgeQueueEntityType = getEdgeQueueTypeByEntityType(alarm.getOriginator().getEntityType());
512   - if (edgeId != null && edgeQueueEntityType != null) {
513   - pushEventToEdge(tenantId, edgeId, EdgeQueueEntityType.ALARM, tbMsg, callback);
  520 + if (edgeQueueEntityType != null) {
  521 + pushEventToEdge(tenantId, alarm.getOriginator(), EdgeQueueEntityType.ALARM, tbMsg, callback);
514 522 }
515 523 break;
516 524 default:
... ...
... ... @@ -21,10 +21,12 @@ import org.springframework.beans.factory.annotation.Autowired;
21 21 import org.springframework.beans.factory.annotation.Value;
22 22 import org.thingsboard.server.common.data.id.EntityId;
23 23 import org.thingsboard.server.common.data.id.TenantId;
  24 +import org.thingsboard.server.common.data.relation.EntityRelation;
24 25 import org.thingsboard.server.dao.relation.RelationService;
25 26
26 27 import javax.annotation.PostConstruct;
27 28 import java.util.Optional;
  29 +import java.util.concurrent.ExecutionException;
28 30
29 31 @Slf4j
30 32 public abstract class AbstractEntityService {
... ... @@ -42,6 +44,16 @@ public abstract class AbstractEntityService {
42 44 sqlDatabaseUsed = "sql".equalsIgnoreCase(databaseType);
43 45 }
44 46
  47 + protected void createRelation(TenantId tenantId, EntityRelation relation) throws ExecutionException, InterruptedException {
  48 + log.debug("Creating relation: {}", relation);
  49 + relationService.saveRelation(tenantId, relation);
  50 + }
  51 +
  52 + protected void deleteRelation(TenantId tenantId, EntityRelation relation) throws ExecutionException, InterruptedException {
  53 + log.debug("Deleting relation: {}", relation);
  54 + relationService.deleteRelation(tenantId, relation);
  55 + }
  56 +
45 57 protected void deleteEntityRelations(TenantId tenantId, EntityId entityId) {
46 58 log.trace("Executing deleteEntityRelations [{}]", entityId);
47 59 relationService.deleteEntityRelations(tenantId, entityId);
... ...
... ... @@ -25,16 +25,23 @@ import com.google.common.util.concurrent.Futures;
25 25 import com.google.common.util.concurrent.ListenableFuture;
26 26 import com.google.common.util.concurrent.MoreExecutors;
27 27 import lombok.extern.slf4j.Slf4j;
  28 +import org.springframework.beans.factory.annotation.Autowired;
28 29 import org.springframework.stereotype.Component;
  30 +import org.thingsboard.server.common.data.Device;
29 31 import org.thingsboard.server.common.data.EntitySubtype;
30 32 import org.thingsboard.server.common.data.EntityType;
31 33 import org.thingsboard.server.common.data.EntityView;
  34 +import org.thingsboard.server.common.data.id.EdgeId;
32 35 import org.thingsboard.server.common.data.id.TenantId;
33 36 import org.thingsboard.server.common.data.page.TextPageLink;
  37 +import org.thingsboard.server.common.data.page.TimePageLink;
  38 +import org.thingsboard.server.common.data.relation.EntityRelation;
  39 +import org.thingsboard.server.common.data.relation.RelationTypeGroup;
34 40 import org.thingsboard.server.dao.DaoUtil;
35 41 import org.thingsboard.server.dao.model.EntitySubtypeEntity;
36 42 import org.thingsboard.server.dao.model.nosql.EntityViewEntity;
37 43 import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao;
  44 +import org.thingsboard.server.dao.relation.RelationDao;
38 45 import org.thingsboard.server.dao.util.NoSqlDao;
39 46
40 47 import javax.annotation.Nullable;
... ... @@ -73,6 +80,9 @@ import static org.thingsboard.server.dao.model.ModelConstants.TENANT_ID_PROPERTY
73 80 @NoSqlDao
74 81 public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<EntityViewEntity, EntityView> implements EntityViewDao {
75 82
  83 + @Autowired
  84 + private RelationDao relationDao;
  85 +
76 86 @Override
77 87 protected Class<EntityViewEntity> getColumnFamilyClass() {
78 88 return EntityViewEntity.class;
... ... @@ -186,30 +196,16 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<Entit
186 196 }
187 197
188 198 @Override
189   - public List<EntityView> findEntityViewsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink) {
190   -// log.debug("Try to find entity views by tenantId [{}], customerId[{}] and pageLink [{}]",
191   -// tenantId, customerId, pageLink);
192   -// List<EntityViewEntity> entityViewEntities = findPageWithTextSearch(new TenantId(tenantId),
193   -// ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_CF,
194   -// Arrays.asList(eq(CUSTOMER_ID_PROPERTY, customerId), eq(TENANT_ID_PROPERTY, tenantId)),
195   -// pageLink);
196   -// log.trace("Found find entity views [{}] by tenantId [{}], customerId [{}] and pageLink [{}]",
197   -// entityViewEntities, tenantId, customerId, pageLink);
198   -// return DaoUtil.convertDataList(entityViewEntities);
199   - throw new UnsupportedOperationException("Cassandra is not supported yet");
  199 + public ListenableFuture<List<EntityView>> findEntityViewsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink) {
  200 + log.debug("Try to find entity views by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink);
  201 + ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(new TenantId(tenantId), new EdgeId(edgeId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE, EntityType.ENTITY_VIEW, pageLink);
  202 + return Futures.transformAsync(relations, input -> {
  203 + List<ListenableFuture<EntityView>> entityViewFutures = new ArrayList<>(input.size());
  204 + for (EntityRelation relation : input) {
  205 + entityViewFutures.add(findByIdAsync(new TenantId(tenantId), relation.getTo().getId()));
  206 + }
  207 + return Futures.successfulAsList(entityViewFutures);
  208 + }, MoreExecutors.directExecutor());
200 209 }
201 210
202   - @Override
203   - public List<EntityView> findEntityViewsByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink) {
204   -// log.debug("Try to find entity views by tenantId [{}], customerId[{}], type [{}] and pageLink [{}]",
205   -// tenantId, customerId, type, pageLink);
206   -// List<EntityViewEntity> entityViewEntities = findPageWithTextSearch(new TenantId(tenantId),
207   -// ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_TYPE_CF,
208   -// Arrays.asList(eq(DEVICE_TYPE_PROPERTY, type), eq(CUSTOMER_ID_PROPERTY, customerId), eq(TENANT_ID_PROPERTY, tenantId)),
209   -// pageLink);
210   -// log.trace("Found find entity views [{}] by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]",
211   -// entityViewEntities, tenantId, customerId, type, pageLink);
212   -// return DaoUtil.convertDataList(entityViewEntities);
213   - throw new UnsupportedOperationException("Cassandra is not supported yet");
214   - }
215 211 }
... ...
... ... @@ -5,7 +5,7 @@
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7 7 *
8   - * http://www.apache.org/licenses/LICENSE-2.0
  8 + * http://www.apache.org/licenses/LICENSE-2.0
9 9 *
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
... ... @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.EntitySubtype;
20 20 import org.thingsboard.server.common.data.EntityView;
21 21 import org.thingsboard.server.common.data.id.TenantId;
22 22 import org.thingsboard.server.common.data.page.TextPageLink;
  23 +import org.thingsboard.server.common.data.page.TimePageLink;
23 24 import org.thingsboard.server.dao.Dao;
24 25
25 26 import java.util.List;
... ... @@ -110,22 +111,8 @@ public interface EntityViewDao extends Dao<EntityView> {
110 111 * @param pageLink the page link
111 112 * @return the list of entity view objects
112 113 */
113   - List<EntityView> findEntityViewsByTenantIdAndEdgeId(UUID tenantId,
114   - UUID edgeId,
115   - TextPageLink pageLink);
116   -
117   - /**
118   - * Find entity views by tenantId, edgeId, type and page link.
119   - *
120   - * @param tenantId the tenantId
121   - * @param edgeId the edgeId
122   - * @param type the type
123   - * @param pageLink the page link
124   - * @return the list of entity view objects
125   - */
126   - List<EntityView> findEntityViewsByTenantIdAndEdgeIdAndType(UUID tenantId,
127   - UUID edgeId,
128   - String type,
129   - TextPageLink pageLink);
  114 + ListenableFuture<List<EntityView>> findEntityViewsByTenantIdAndEdgeId(UUID tenantId,
  115 + UUID edgeId,
  116 + TimePageLink pageLink);
130 117
131 118 }
... ...
... ... @@ -30,10 +30,12 @@ import org.springframework.cache.annotation.Cacheable;
30 30 import org.springframework.cache.annotation.Caching;
31 31 import org.springframework.stereotype.Service;
32 32 import org.thingsboard.server.common.data.Customer;
  33 +import org.thingsboard.server.common.data.Device;
33 34 import org.thingsboard.server.common.data.EntitySubtype;
34 35 import org.thingsboard.server.common.data.EntityType;
35 36 import org.thingsboard.server.common.data.EntityView;
36 37 import org.thingsboard.server.common.data.Tenant;
  38 +import org.thingsboard.server.common.data.edge.Edge;
37 39 import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery;
38 40 import org.thingsboard.server.common.data.id.CustomerId;
39 41 import org.thingsboard.server.common.data.id.EdgeId;
... ... @@ -42,9 +44,13 @@ import org.thingsboard.server.common.data.id.EntityViewId;
42 44 import org.thingsboard.server.common.data.id.TenantId;
43 45 import org.thingsboard.server.common.data.page.TextPageData;
44 46 import org.thingsboard.server.common.data.page.TextPageLink;
  47 +import org.thingsboard.server.common.data.page.TimePageData;
  48 +import org.thingsboard.server.common.data.page.TimePageLink;
45 49 import org.thingsboard.server.common.data.relation.EntityRelation;
46 50 import org.thingsboard.server.common.data.relation.EntitySearchDirection;
  51 +import org.thingsboard.server.common.data.relation.RelationTypeGroup;
47 52 import org.thingsboard.server.dao.customer.CustomerDao;
  53 +import org.thingsboard.server.dao.edge.EdgeService;
48 54 import org.thingsboard.server.dao.entity.AbstractEntityService;
49 55 import org.thingsboard.server.dao.exception.DataValidationException;
50 56 import org.thingsboard.server.dao.service.DataValidator;
... ... @@ -58,6 +64,7 @@ import java.util.Collections;
58 64 import java.util.Comparator;
59 65 import java.util.List;
60 66 import java.util.Optional;
  67 +import java.util.concurrent.ExecutionException;
61 68 import java.util.stream.Collectors;
62 69
63 70 import static org.thingsboard.server.common.data.CacheConstants.ENTITY_VIEW_CACHE;
... ... @@ -89,6 +96,9 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
89 96 private CustomerDao customerDao;
90 97
91 98 @Autowired
  99 + private EdgeService edgeService;
  100 +
  101 + @Autowired
92 102 private CacheManager cacheManager;
93 103
94 104 @Caching(evict = {
... ... @@ -285,47 +295,56 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
285 295 }, MoreExecutors.directExecutor());
286 296 }
287 297
288   -
289   - @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}")
290 298 @Override
291 299 public EntityView assignEntityViewToEdge(TenantId tenantId, EntityViewId entityViewId, EdgeId edgeId) {
292 300 EntityView entityView = findEntityViewById(tenantId, entityViewId);
293   - entityView.setEdgeId(edgeId);
294   - return saveEntityView(entityView);
  301 + Edge edge = edgeService.findEdgeById(tenantId, edgeId);
  302 + if (edge == null) {
  303 + throw new DataValidationException("Can't assign entityView to non-existent edge!");
  304 + }
  305 + if (!edge.getTenantId().getId().equals(entityView.getTenantId().getId())) {
  306 + throw new DataValidationException("Can't assign entityView to edge from different tenant!");
  307 + }
  308 + try {
  309 + createRelation(tenantId, new EntityRelation(edgeId, entityViewId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE));
  310 + } catch (ExecutionException | InterruptedException e) {
  311 + log.warn("[{}] Failed to create entityView relation. Edge Id: [{}]", entityViewId, edgeId);
  312 + throw new RuntimeException(e);
  313 + }
  314 + return entityView;
295 315 }
296 316
297   - @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}")
298 317 @Override
299   - public EntityView unassignEntityViewFromEdge(TenantId tenantId, EntityViewId entityViewId) {
  318 + public EntityView unassignEntityViewFromEdge(TenantId tenantId, EntityViewId entityViewId, EdgeId edgeId) {
300 319 EntityView entityView = findEntityViewById(tenantId, entityViewId);
301   - entityView.setEdgeId(null);
302   - return saveEntityView(entityView);
303   - }
304   -
305   - @Override
306   - public TextPageData<EntityView> findEntityViewsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId,
307   - TextPageLink pageLink) {
308   - log.trace("Executing findEntityViewsByTenantIdAndEdgeId, tenantId [{}], edgeId [{}]," +
309   - " pageLink [{}]", tenantId, edgeId, pageLink);
310   - validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
311   - validateId(edgeId, INCORRECT_EDGE_ID + edgeId);
312   - validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink);
313   - List<EntityView> entityViews = entityViewDao.findEntityViewsByTenantIdAndEdgeId(tenantId.getId(),
314   - edgeId.getId(), pageLink);
315   - return new TextPageData<>(entityViews, pageLink);
  320 + Edge edge = edgeService.findEdgeById(tenantId, edgeId);
  321 + if (edge == null) {
  322 + throw new DataValidationException("Can't unassign entityView from non-existent edge!");
  323 + }
  324 + try {
  325 + deleteRelation(tenantId, new EntityRelation(edgeId, entityViewId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE));
  326 + } catch (ExecutionException | InterruptedException e) {
  327 + log.warn("[{}] Failed to delete entityView relation. Edge Id: [{}]", entityViewId, edgeId);
  328 + throw new RuntimeException(e);
  329 + }
  330 + return entityView;
316 331 }
317 332
318 333 @Override
319   - public TextPageData<EntityView> findEntityViewsByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink) {
320   - log.trace("Executing findEntityViewsByTenantIdAndEdgeIdAndType, tenantId [{}], edgeId [{}]," +
321   - " pageLink [{}], type [{}]", tenantId, edgeId, pageLink, type);
  334 + public ListenableFuture<TimePageData<EntityView>> findEntityViewsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId,
  335 + TimePageLink pageLink) {
  336 + log.trace("Executing findEntityViewsByTenantIdAndEdgeId, tenantId [{}], edgeId [{}], pageLink [{}]", tenantId, edgeId, pageLink);
322 337 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
323 338 validateId(edgeId, INCORRECT_EDGE_ID + edgeId);
324 339 validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink);
325   - validateString(type, "Incorrect type " + type);
326   - List<EntityView> entityViews = entityViewDao.findEntityViewsByTenantIdAndEdgeIdAndType(tenantId.getId(),
327   - edgeId.getId(), type, pageLink);
328   - return new TextPageData<>(entityViews, pageLink);
  340 + ListenableFuture<List<EntityView>> entityViews = entityViewDao.findEntityViewsByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink);
  341 + return Futures.transform(entityViews, new Function<List<EntityView>, TimePageData<EntityView>>() {
  342 + @Nullable
  343 + @Override
  344 + public TimePageData<EntityView> apply(@Nullable List<EntityView> entityViews) {
  345 + return new TimePageData<>(entityViews, pageLink);
  346 + }
  347 + }, MoreExecutors.directExecutor());
329 348 }
330 349
331 350 private DataValidator<EntityView> entityViewValidator =
... ...
... ... @@ -142,7 +142,6 @@ public class ModelConstants {
142 142 public static final String DEVICE_TYPE_PROPERTY = "type";
143 143 public static final String DEVICE_LABEL_PROPERTY = "label";
144 144 public static final String DEVICE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
145   - public static final String DEVICE_EDGE_ID_PROPERTY = "edge_id";
146 145 public static final String DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_and_search_text";
147 146 public static final String DEVICE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_by_type_and_search_text";
148 147 public static final String DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_customer_and_search_text";
... ... @@ -158,7 +157,6 @@ public class ModelConstants {
158 157 public static final String ENTITY_VIEW_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
159 158 public static final String ENTITY_VIEW_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY;
160 159 public static final String ENTITY_VIEW_NAME_PROPERTY = DEVICE_NAME_PROPERTY;
161   - public static final String ENTITY_VIEW_EDGE_ID_PROPERTY = "edge_id";
162 160 public static final String ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_CF = "entity_view_by_tenant_and_customer";
163 161 public static final String ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_TYPE_CF = "entity_view_by_tenant_and_customer_and_type";
164 162 public static final String ENTITY_VIEW_BY_TENANT_AND_ENTITY_ID_CF = "entity_view_by_tenant_and_entity_id";
... ... @@ -206,7 +204,6 @@ public class ModelConstants {
206 204 public static final String ASSET_TYPE_PROPERTY = "type";
207 205 public static final String ASSET_LABEL_PROPERTY = "label";
208 206 public static final String ASSET_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
209   - public static final String ASSET_EDGE_ID_PROPERTY = "edge_id";
210 207
211 208 public static final String ASSET_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_tenant_and_search_text";
212 209 public static final String ASSET_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_tenant_by_type_and_search_text";
... ...
... ... @@ -25,7 +25,6 @@ import lombok.ToString;
25 25 import org.thingsboard.server.common.data.asset.Asset;
26 26 import org.thingsboard.server.common.data.id.AssetId;
27 27 import org.thingsboard.server.common.data.id.CustomerId;
28   -import org.thingsboard.server.common.data.id.EdgeId;
29 28 import org.thingsboard.server.common.data.id.TenantId;
30 29 import org.thingsboard.server.dao.model.SearchTextEntity;
31 30 import org.thingsboard.server.dao.model.type.JsonCodec;
... ... @@ -35,11 +34,10 @@ import java.util.UUID;
35 34 import static org.thingsboard.server.dao.model.ModelConstants.ASSET_ADDITIONAL_INFO_PROPERTY;
36 35 import static org.thingsboard.server.dao.model.ModelConstants.ASSET_COLUMN_FAMILY_NAME;
37 36 import static org.thingsboard.server.dao.model.ModelConstants.ASSET_CUSTOMER_ID_PROPERTY;
38   -import static org.thingsboard.server.dao.model.ModelConstants.ASSET_EDGE_ID_PROPERTY;
  37 +import static org.thingsboard.server.dao.model.ModelConstants.ASSET_LABEL_PROPERTY;
39 38 import static org.thingsboard.server.dao.model.ModelConstants.ASSET_NAME_PROPERTY;
40 39 import static org.thingsboard.server.dao.model.ModelConstants.ASSET_TENANT_ID_PROPERTY;
41 40 import static org.thingsboard.server.dao.model.ModelConstants.ASSET_TYPE_PROPERTY;
42   -import static org.thingsboard.server.dao.model.ModelConstants.ASSET_LABEL_PROPERTY;
43 41 import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY;
44 42 import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY;
45 43
... ... @@ -64,10 +62,6 @@ public final class AssetEntity implements SearchTextEntity<Asset> {
64 62 @Column(name = ASSET_TYPE_PROPERTY)
65 63 private String type;
66 64
67   - @PartitionKey(value = 4)
68   - @Column(name = ASSET_EDGE_ID_PROPERTY)
69   - private UUID edgeId;
70   -
71 65 @Column(name = ASSET_NAME_PROPERTY)
72 66 private String name;
73 67
... ... @@ -94,9 +88,6 @@ public final class AssetEntity implements SearchTextEntity<Asset> {
94 88 if (asset.getCustomerId() != null) {
95 89 this.customerId = asset.getCustomerId().getId();
96 90 }
97   - if (asset.getEdgeId() != null) {
98   - this.edgeId = asset.getEdgeId().getId();
99   - }
100 91 this.name = asset.getName();
101 92 this.type = asset.getType();
102 93 this.label = asset.getLabel();
... ... @@ -127,14 +118,6 @@ public final class AssetEntity implements SearchTextEntity<Asset> {
127 118 this.customerId = customerId;
128 119 }
129 120
130   - public UUID getEdgeId() {
131   - return edgeId;
132   - }
133   -
134   - public void setEdgeId(UUID edgeId) {
135   - this.edgeId = edgeId;
136   - }
137   -
138 121 public String getName() {
139 122 return name;
140 123 }
... ... @@ -183,9 +166,6 @@ public final class AssetEntity implements SearchTextEntity<Asset> {
183 166 if (customerId != null) {
184 167 asset.setCustomerId(new CustomerId(customerId));
185 168 }
186   - if (edgeId != null) {
187   - asset.setEdgeId(new EdgeId(edgeId));
188   - }
189 169 asset.setName(name);
190 170 asset.setType(type);
191 171 asset.setLabel(label);
... ...
... ... @@ -25,14 +25,21 @@ import lombok.ToString;
25 25 import org.thingsboard.server.common.data.Device;
26 26 import org.thingsboard.server.common.data.id.CustomerId;
27 27 import org.thingsboard.server.common.data.id.DeviceId;
28   -import org.thingsboard.server.common.data.id.EdgeId;
29 28 import org.thingsboard.server.common.data.id.TenantId;
30 29 import org.thingsboard.server.dao.model.SearchTextEntity;
31 30 import org.thingsboard.server.dao.model.type.JsonCodec;
32 31
33 32 import java.util.UUID;
34 33
35   -import static org.thingsboard.server.dao.model.ModelConstants.*;
  34 +import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_ADDITIONAL_INFO_PROPERTY;
  35 +import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_COLUMN_FAMILY_NAME;
  36 +import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_CUSTOMER_ID_PROPERTY;
  37 +import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_LABEL_PROPERTY;
  38 +import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_NAME_PROPERTY;
  39 +import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_TENANT_ID_PROPERTY;
  40 +import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_TYPE_PROPERTY;
  41 +import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY;
  42 +import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY;
36 43
37 44 @Table(name = DEVICE_COLUMN_FAMILY_NAME)
38 45 @EqualsAndHashCode
... ... @@ -55,10 +62,6 @@ public final class DeviceEntity implements SearchTextEntity<Device> {
55 62 @Column(name = DEVICE_TYPE_PROPERTY)
56 63 private String type;
57 64
58   - @PartitionKey(value = 4)
59   - @Column(name = DEVICE_EDGE_ID_PROPERTY)
60   - private UUID edgeId;
61   -
62 65 @Column(name = DEVICE_NAME_PROPERTY)
63 66 private String name;
64 67
... ... @@ -85,9 +88,6 @@ public final class DeviceEntity implements SearchTextEntity<Device> {
85 88 if (device.getCustomerId() != null) {
86 89 this.customerId = device.getCustomerId().getId();
87 90 }
88   - if (device.getEdgeId() != null) {
89   - this.edgeId = device.getEdgeId().getId();
90   - }
91 91 this.name = device.getName();
92 92 this.type = device.getType();
93 93 this.label = device.getLabel();
... ... @@ -118,14 +118,6 @@ public final class DeviceEntity implements SearchTextEntity<Device> {
118 118 this.customerId = customerId;
119 119 }
120 120
121   - public UUID getEdgeId() {
122   - return edgeId;
123   - }
124   -
125   - public void setEdgeId(UUID edgeId) {
126   - this.edgeId = edgeId;
127   - }
128   -
129 121 public String getName() {
130 122 return name;
131 123 }
... ... @@ -174,9 +166,6 @@ public final class DeviceEntity implements SearchTextEntity<Device> {
174 166 if (customerId != null) {
175 167 device.setCustomerId(new CustomerId(customerId));
176 168 }
177   - if (edgeId != null) {
178   - device.setEdgeId(new EdgeId(edgeId));
179   - }
180 169 device.setName(name);
181 170 device.setType(type);
182 171 device.setLabel(label);
... ...
... ... @@ -29,7 +29,6 @@ import org.hibernate.annotations.Type;
29 29 import org.thingsboard.server.common.data.EntityType;
30 30 import org.thingsboard.server.common.data.EntityView;
31 31 import org.thingsboard.server.common.data.id.CustomerId;
32   -import org.thingsboard.server.common.data.id.EdgeId;
33 32 import org.thingsboard.server.common.data.id.EntityIdFactory;
34 33 import org.thingsboard.server.common.data.id.EntityViewId;
35 34 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -42,7 +41,6 @@ import javax.persistence.Enumerated;
42 41 import java.io.IOException;
43 42 import java.util.UUID;
44 43
45   -import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_EDGE_ID_PROPERTY;
46 44 import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_TYPE_PROPERTY;
47 45 import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_TYPE_PROPERTY;
48 46 import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_TABLE_FAMILY_NAME;
... ... @@ -71,10 +69,6 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
71 69 @Column(name = DEVICE_TYPE_PROPERTY)
72 70 private String type;
73 71
74   - @PartitionKey(value = 4)
75   - @Column(name = DEVICE_EDGE_ID_PROPERTY)
76   - private UUID edgeId;
77   -
78 72 @Enumerated(EnumType.STRING)
79 73 @Column(name = ENTITY_TYPE_PROPERTY)
80 74 private EntityType entityType;
... ... @@ -121,9 +115,6 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
121 115 if (entityView.getCustomerId() != null) {
122 116 this.customerId = entityView.getCustomerId().getId();
123 117 }
124   - if (entityView.getEdgeId() != null) {
125   - this.edgeId = entityView.getEdgeId().getId();
126   - }
127 118 this.type = entityView.getType();
128 119 this.name = entityView.getName();
129 120 try {
... ... @@ -155,9 +146,6 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
155 146 if (customerId != null) {
156 147 entityView.setCustomerId(new CustomerId(customerId));
157 148 }
158   - if (edgeId != null) {
159   - entityView.setEdgeId(new EdgeId(edgeId));
160   - }
161 149 entityView.setType(type);
162 150 entityView.setName(name);
163 151 try {
... ...
... ... @@ -25,7 +25,6 @@ import org.thingsboard.server.common.data.UUIDConverter;
25 25 import org.thingsboard.server.common.data.asset.Asset;
26 26 import org.thingsboard.server.common.data.id.AssetId;
27 27 import org.thingsboard.server.common.data.id.CustomerId;
28   -import org.thingsboard.server.common.data.id.EdgeId;
29 28 import org.thingsboard.server.common.data.id.TenantId;
30 29 import org.thingsboard.server.dao.model.BaseSqlEntity;
31 30 import org.thingsboard.server.dao.model.ModelConstants;
... ... @@ -38,11 +37,10 @@ import javax.persistence.Table;
38 37
39 38 import static org.thingsboard.server.dao.model.ModelConstants.ASSET_COLUMN_FAMILY_NAME;
40 39 import static org.thingsboard.server.dao.model.ModelConstants.ASSET_CUSTOMER_ID_PROPERTY;
41   -import static org.thingsboard.server.dao.model.ModelConstants.ASSET_EDGE_ID_PROPERTY;
  40 +import static org.thingsboard.server.dao.model.ModelConstants.ASSET_LABEL_PROPERTY;
42 41 import static org.thingsboard.server.dao.model.ModelConstants.ASSET_NAME_PROPERTY;
43 42 import static org.thingsboard.server.dao.model.ModelConstants.ASSET_TENANT_ID_PROPERTY;
44 43 import static org.thingsboard.server.dao.model.ModelConstants.ASSET_TYPE_PROPERTY;
45   -import static org.thingsboard.server.dao.model.ModelConstants.ASSET_LABEL_PROPERTY;
46 44 import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY;
47 45
48 46 @Data
... ... @@ -58,9 +56,6 @@ public final class AssetEntity extends BaseSqlEntity<Asset> implements SearchTex
58 56 @Column(name = ASSET_CUSTOMER_ID_PROPERTY)
59 57 private String customerId;
60 58
61   - @Column(name = ASSET_EDGE_ID_PROPERTY)
62   - private String edgeId;
63   -
64 59 @Column(name = ASSET_NAME_PROPERTY)
65 60 private String name;
66 61
... ... @@ -91,9 +86,6 @@ public final class AssetEntity extends BaseSqlEntity<Asset> implements SearchTex
91 86 if (asset.getCustomerId() != null) {
92 87 this.customerId = UUIDConverter.fromTimeUUID(asset.getCustomerId().getId());
93 88 }
94   - if (asset.getEdgeId() != null) {
95   - this.edgeId = UUIDConverter.fromTimeUUID(asset.getEdgeId().getId());
96   - }
97 89 this.name = asset.getName();
98 90 this.type = asset.getType();
99 91 this.label = asset.getLabel();
... ... @@ -124,9 +116,6 @@ public final class AssetEntity extends BaseSqlEntity<Asset> implements SearchTex
124 116 if (customerId != null) {
125 117 asset.setCustomerId(new CustomerId(UUIDConverter.fromString(customerId)));
126 118 }
127   - if (edgeId != null) {
128   - asset.setEdgeId(new EdgeId(UUIDConverter.fromString(edgeId)));
129   - }
130 119 asset.setName(name);
131 120 asset.setType(type);
132 121 asset.setLabel(label);
... ...
... ... @@ -24,7 +24,6 @@ import org.hibernate.annotations.TypeDef;
24 24 import org.thingsboard.server.common.data.Device;
25 25 import org.thingsboard.server.common.data.id.CustomerId;
26 26 import org.thingsboard.server.common.data.id.DeviceId;
27   -import org.thingsboard.server.common.data.id.EdgeId;
28 27 import org.thingsboard.server.common.data.id.TenantId;
29 28 import org.thingsboard.server.dao.model.BaseSqlEntity;
30 29 import org.thingsboard.server.dao.model.ModelConstants;
... ... @@ -48,9 +47,6 @@ public final class DeviceEntity extends BaseSqlEntity<Device> implements SearchT
48 47 @Column(name = ModelConstants.DEVICE_CUSTOMER_ID_PROPERTY)
49 48 private String customerId;
50 49
51   - @Column(name = ModelConstants.DEVICE_EDGE_ID_PROPERTY)
52   - private String edgeId;
53   -
54 50 @Column(name = ModelConstants.DEVICE_TYPE_PROPERTY)
55 51 private String type;
56 52
... ... @@ -81,9 +77,6 @@ public final class DeviceEntity extends BaseSqlEntity<Device> implements SearchT
81 77 if (device.getCustomerId() != null) {
82 78 this.customerId = toString(device.getCustomerId().getId());
83 79 }
84   - if (device.getEdgeId() != null) {
85   - this.edgeId = toString(device.getEdgeId().getId());
86   - }
87 80 this.name = device.getName();
88 81 this.type = device.getType();
89 82 this.label = device.getLabel();
... ... @@ -110,9 +103,6 @@ public final class DeviceEntity extends BaseSqlEntity<Device> implements SearchT
110 103 if (customerId != null) {
111 104 device.setCustomerId(new CustomerId(toUUID(customerId)));
112 105 }
113   - if (edgeId != null) {
114   - device.setEdgeId(new EdgeId(toUUID(edgeId)));
115   - }
116 106 device.setName(name);
117 107 device.setType(type);
118 108 device.setLabel(label);
... ...
... ... @@ -26,7 +26,6 @@ import org.hibernate.annotations.TypeDef;
26 26 import org.thingsboard.server.common.data.EntityType;
27 27 import org.thingsboard.server.common.data.EntityView;
28 28 import org.thingsboard.server.common.data.id.CustomerId;
29   -import org.thingsboard.server.common.data.id.EdgeId;
30 29 import org.thingsboard.server.common.data.id.EntityIdFactory;
31 30 import org.thingsboard.server.common.data.id.EntityViewId;
32 31 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -66,9 +65,6 @@ public class EntityViewEntity extends BaseSqlEntity<EntityView> implements Searc
66 65 @Column(name = ModelConstants.ENTITY_VIEW_CUSTOMER_ID_PROPERTY)
67 66 private String customerId;
68 67
69   - @Column(name = ModelConstants.ENTITY_VIEW_EDGE_ID_PROPERTY)
70   - private String edgeId;
71   -
72 68 @Column(name = ModelConstants.DEVICE_TYPE_PROPERTY)
73 69 private String type;
74 70
... ... @@ -111,9 +107,6 @@ public class EntityViewEntity extends BaseSqlEntity<EntityView> implements Searc
111 107 if (entityView.getCustomerId() != null) {
112 108 this.customerId = toString(entityView.getCustomerId().getId());
113 109 }
114   - if (entityView.getEdgeId() != null) {
115   - this.edgeId = toString(entityView.getEdgeId().getId());
116   - }
117 110 this.type = entityView.getType();
118 111 this.name = entityView.getName();
119 112 try {
... ... @@ -151,9 +144,6 @@ public class EntityViewEntity extends BaseSqlEntity<EntityView> implements Searc
151 144 if (customerId != null) {
152 145 entityView.setCustomerId(new CustomerId(toUUID(customerId)));
153 146 }
154   - if (edgeId != null) {
155   - entityView.setEdgeId(new EdgeId(toUUID(edgeId)));
156   - }
157 147 entityView.setType(type);
158 148 entityView.setName(name);
159 149 try {
... ...
... ... @@ -467,8 +467,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
467 467 return Futures.transform(ruleChains, new Function<List<RuleChain>, TimePageData<RuleChain>>() {
468 468 @Nullable
469 469 @Override
470   - public TimePageData<RuleChain> apply(@Nullable List<RuleChain> ruleChain) {
471   - return new TimePageData<>(ruleChain, pageLink);
  470 + public TimePageData<RuleChain> apply(@Nullable List<RuleChain> ruleChains) {
  471 + return new TimePageData<>(ruleChains, pageLink);
472 472 }
473 473 }, MoreExecutors.directExecutor());
474 474 }
... ... @@ -557,15 +557,6 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
557 557 ruleNodeDao.removeById(tenantId, entityId.getId());
558 558 }
559 559
560   - private void createRelation(TenantId tenantId, EntityRelation relation) throws ExecutionException, InterruptedException {
561   - log.debug("Creating relation: {}", relation);
562   - relationService.saveRelation(tenantId, relation);
563   - }
564   -
565   - private void deleteRelation(TenantId tenantId, EntityRelation relation) throws ExecutionException, InterruptedException {
566   - log.debug("Deleting relation: {}", relation);
567   - relationService.deleteRelation(tenantId, relation);
568   - }
569 560
570 561 private DataValidator<RuleChain> ruleChainValidator =
571 562 new DataValidator<RuleChain>() {
... ...
... ... @@ -96,7 +96,7 @@ public class CassandraRuleChainDao extends CassandraAbstractSearchTextDao<RuleCh
96 96 @Override
97 97 public ListenableFuture<List<RuleChain>> findRuleChainsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink) {
98 98 log.debug("Try to find rule chains by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink);
99   - ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(new TenantId(tenantId), new EdgeId(edgeId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE, EntityType.DASHBOARD, pageLink);
  99 + ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(new TenantId(tenantId), new EdgeId(edgeId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE, EntityType.RULE_CHAIN, pageLink);
100 100 return Futures.transformAsync(relations, input -> {
101 101 List<ListenableFuture<RuleChain>> ruleChainFutures = new ArrayList<>(input.size());
102 102 for (EntityRelation relation : input) {
... ...
... ... @@ -77,26 +77,4 @@ public interface AssetRepository extends CrudRepository<AssetEntity, String> {
77 77
78 78 @Query("SELECT DISTINCT a.type FROM AssetEntity a WHERE a.tenantId = :tenantId")
79 79 List<String> findTenantAssetTypes(@Param("tenantId") String tenantId);
80   -
81   - @Query("SELECT a FROM AssetEntity a WHERE a.tenantId = :tenantId " +
82   - "AND a.edgeId = :edgeId " +
83   - "AND LOWER(a.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " +
84   - "AND a.id > :idOffset ORDER BY a.id")
85   - List<AssetEntity> findByTenantIdAndEdgeId(@Param("tenantId") String tenantId,
86   - @Param("edgeId") String edgeId,
87   - @Param("textSearch") String textSearch,
88   - @Param("idOffset") String idOffset,
89   - Pageable pageable);
90   -
91   - @Query("SELECT a FROM AssetEntity a WHERE a.tenantId = :tenantId " +
92   - "AND a.edgeId = :edgeId AND a.type = :type " +
93   - "AND LOWER(a.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " +
94   - "AND a.id > :idOffset ORDER BY a.id")
95   - List<AssetEntity> findByTenantIdAndEdgeIdAndType(@Param("tenantId") String tenantId,
96   - @Param("edgeId") String edgeId,
97   - @Param("type") String type,
98   - @Param("textSearch") String textSearch,
99   - @Param("idOffset") String idOffset,
100   - Pageable pageable);
101   -
102 80 }
... ...
... ... @@ -15,19 +15,28 @@
15 15 */
16 16 package org.thingsboard.server.dao.sql.asset;
17 17
  18 +import com.google.common.util.concurrent.Futures;
18 19 import com.google.common.util.concurrent.ListenableFuture;
  20 +import com.google.common.util.concurrent.MoreExecutors;
  21 +import lombok.extern.slf4j.Slf4j;
19 22 import org.springframework.beans.factory.annotation.Autowired;
20 23 import org.springframework.data.domain.PageRequest;
21 24 import org.springframework.data.repository.CrudRepository;
22 25 import org.springframework.stereotype.Component;
  26 +import org.thingsboard.server.common.data.Device;
23 27 import org.thingsboard.server.common.data.EntitySubtype;
24 28 import org.thingsboard.server.common.data.EntityType;
25 29 import org.thingsboard.server.common.data.asset.Asset;
  30 +import org.thingsboard.server.common.data.id.EdgeId;
26 31 import org.thingsboard.server.common.data.id.TenantId;
27 32 import org.thingsboard.server.common.data.page.TextPageLink;
  33 +import org.thingsboard.server.common.data.page.TimePageLink;
  34 +import org.thingsboard.server.common.data.relation.EntityRelation;
  35 +import org.thingsboard.server.common.data.relation.RelationTypeGroup;
28 36 import org.thingsboard.server.dao.DaoUtil;
29 37 import org.thingsboard.server.dao.asset.AssetDao;
30 38 import org.thingsboard.server.dao.model.sql.AssetEntity;
  39 +import org.thingsboard.server.dao.relation.RelationDao;
31 40 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
32 41 import org.thingsboard.server.dao.util.SqlDao;
33 42
... ... @@ -47,11 +56,15 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID_STR;
47 56 */
48 57 @Component
49 58 @SqlDao
  59 +@Slf4j
50 60 public class JpaAssetDao extends JpaAbstractSearchTextDao<AssetEntity, Asset> implements AssetDao {
51 61
52 62 @Autowired
53 63 private AssetRepository assetRepository;
54 64
  65 + @Autowired
  66 + private RelationDao relationDao;
  67 +
55 68 @Override
56 69 protected Class<AssetEntity> getEntityClass() {
57 70 return AssetEntity.class;
... ... @@ -141,27 +154,16 @@ public class JpaAssetDao extends JpaAbstractSearchTextDao<AssetEntity, Asset> im
141 154 }
142 155
143 156 @Override
144   - public List<Asset> findAssetsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink) {
145   - return DaoUtil.convertDataList(assetRepository
146   - .findByTenantIdAndEdgeId(
147   - fromTimeUUID(tenantId),
148   - fromTimeUUID(edgeId),
149   - Objects.toString(pageLink.getTextSearch(), ""),
150   - pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()),
151   - PageRequest.of(0, pageLink.getLimit())));
152   - }
153   -
154   -
155   - @Override
156   - public List<Asset> findAssetsByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink) {
157   - return DaoUtil.convertDataList(assetRepository
158   - .findByTenantIdAndEdgeIdAndType(
159   - fromTimeUUID(tenantId),
160   - fromTimeUUID(edgeId),
161   - type,
162   - Objects.toString(pageLink.getTextSearch(), ""),
163   - pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()),
164   - PageRequest.of(0, pageLink.getLimit())));
  157 + public ListenableFuture<List<Asset>> findAssetsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink) {
  158 + log.debug("Try to find assets by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink);
  159 + ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(new TenantId(tenantId), new EdgeId(edgeId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE, EntityType.ASSET, pageLink);
  160 + return Futures.transformAsync(relations, input -> {
  161 + List<ListenableFuture<Asset>> assetFutures = new ArrayList<>(input.size());
  162 + for (EntityRelation relation : input) {
  163 + assetFutures.add(findByIdAsync(new TenantId(tenantId), relation.getTo().getId()));
  164 + }
  165 + return Futures.successfulAsList(assetFutures);
  166 + }, MoreExecutors.directExecutor());
165 167 }
166 168
167 169 }
... ...
... ... @@ -85,26 +85,4 @@ public interface DeviceRepository extends CrudRepository<DeviceEntity, String> {
85 85 List<DeviceEntity> findDevicesByTenantIdAndCustomerIdAndIdIn(String tenantId, String customerId, List<String> deviceIds);
86 86
87 87 List<DeviceEntity> findDevicesByTenantIdAndIdIn(String tenantId, List<String> deviceIds);
88   -
89   - @Query("SELECT d FROM DeviceEntity d WHERE d.tenantId = :tenantId " +
90   - "AND d.edgeId = :edgeId " +
91   - "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:searchText, '%')) " +
92   - "AND d.id > :idOffset ORDER BY d.id")
93   - List<DeviceEntity> findByTenantIdAndEdgeId(@Param("tenantId") String tenantId,
94   - @Param("edgeId") String edgeId,
95   - @Param("searchText") String searchText,
96   - @Param("idOffset") String idOffset,
97   - Pageable pageable);
98   -
99   - @Query("SELECT d FROM DeviceEntity d WHERE d.tenantId = :tenantId " +
100   - "AND d.edgeId = :edgeId " +
101   - "AND d.type = :type " +
102   - "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " +
103   - "AND d.id > :idOffset ORDER BY d.id")
104   - List<DeviceEntity> findByTenantIdAndEdgeIdAndType(@Param("tenantId") String tenantId,
105   - @Param("edgeId") String edgeId,
106   - @Param("type") String type,
107   - @Param("textSearch") String textSearch,
108   - @Param("idOffset") String idOffset,
109   - Pageable pageable);
110 88 }
... ...
... ... @@ -15,7 +15,10 @@
15 15 */
16 16 package org.thingsboard.server.dao.sql.device;
17 17
  18 +import com.google.common.util.concurrent.Futures;
18 19 import com.google.common.util.concurrent.ListenableFuture;
  20 +import com.google.common.util.concurrent.MoreExecutors;
  21 +import lombok.extern.slf4j.Slf4j;
19 22 import org.springframework.beans.factory.annotation.Autowired;
20 23 import org.springframework.data.domain.PageRequest;
21 24 import org.springframework.data.repository.CrudRepository;
... ... @@ -25,11 +28,17 @@ import org.thingsboard.server.common.data.Device;
25 28 import org.thingsboard.server.common.data.EntitySubtype;
26 29 import org.thingsboard.server.common.data.EntityType;
27 30 import org.thingsboard.server.common.data.UUIDConverter;
  31 +import org.thingsboard.server.common.data.id.EdgeId;
28 32 import org.thingsboard.server.common.data.id.TenantId;
29 33 import org.thingsboard.server.common.data.page.TextPageLink;
  34 +import org.thingsboard.server.common.data.page.TimePageLink;
  35 +import org.thingsboard.server.common.data.relation.EntityRelation;
  36 +import org.thingsboard.server.common.data.relation.RelationTypeGroup;
  37 +import org.thingsboard.server.common.data.rule.RuleChain;
30 38 import org.thingsboard.server.dao.DaoUtil;
31 39 import org.thingsboard.server.dao.device.DeviceDao;
32 40 import org.thingsboard.server.dao.model.sql.DeviceEntity;
  41 +import org.thingsboard.server.dao.relation.RelationDao;
33 42 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
34 43 import org.thingsboard.server.dao.util.SqlDao;
35 44
... ... @@ -49,11 +58,15 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID_STR;
49 58 */
50 59 @Component
51 60 @SqlDao
  61 +@Slf4j
52 62 public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device> implements DeviceDao {
53 63
54 64 @Autowired
55 65 private DeviceRepository deviceRepository;
56 66
  67 + @Autowired
  68 + private RelationDao relationDao;
  69 +
57 70 @Override
58 71 protected Class<DeviceEntity> getEntityClass() {
59 72 return DeviceEntity.class;
... ... @@ -149,28 +162,16 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device>
149 162 return list;
150 163 }
151 164
152   -
153 165 @Override
154   - public List<Device> findDevicesByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink) {
155   - return DaoUtil.convertDataList(
156   - deviceRepository.findByTenantIdAndEdgeId(
157   - fromTimeUUID(tenantId),
158   - fromTimeUUID(edgeId),
159   - Objects.toString(pageLink.getTextSearch(), ""),
160   - pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()),
161   - PageRequest.of(0, pageLink.getLimit())));
162   - }
163   -
164   - @Override
165   - public List<Device> findDevicesByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink) {
166   - return DaoUtil.convertDataList(
167   - deviceRepository.findByTenantIdAndEdgeIdAndType(
168   - fromTimeUUID(tenantId),
169   - fromTimeUUID(edgeId),
170   - type,
171   - Objects.toString(pageLink.getTextSearch(), ""),
172   - pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()),
173   - PageRequest.of(0, pageLink.getLimit())));
  166 + public ListenableFuture<List<Device>> findDevicesByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink) {
  167 + log.debug("Try to find devices by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink);
  168 + ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(new TenantId(tenantId), new EdgeId(edgeId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE, EntityType.DEVICE, pageLink);
  169 + return Futures.transformAsync(relations, input -> {
  170 + List<ListenableFuture<Device>> deviceFutures = new ArrayList<>(input.size());
  171 + for (EntityRelation relation : input) {
  172 + deviceFutures.add(findByIdAsync(new TenantId(tenantId), relation.getTo().getId()));
  173 + }
  174 + return Futures.successfulAsList(deviceFutures);
  175 + }, MoreExecutors.directExecutor());
174 176 }
175   -
176 177 }
... ...
... ... @@ -76,26 +76,4 @@ public interface EntityViewRepository extends CrudRepository<EntityViewEntity, S
76 76
77 77 @Query("SELECT DISTINCT ev.type FROM EntityViewEntity ev WHERE ev.tenantId = :tenantId")
78 78 List<String> findTenantEntityViewTypes(@Param("tenantId") String tenantId);
79   -
80   - @Query("SELECT e FROM EntityViewEntity e WHERE e.tenantId = :tenantId " +
81   - "AND e.edgeId = :edgeId " +
82   - "AND LOWER(e.searchText) LIKE LOWER(CONCAT(:searchText, '%')) " +
83   - "AND e.id > :idOffset ORDER BY e.id")
84   - List<EntityViewEntity> findByTenantIdAndEdgeId(@Param("tenantId") String tenantId,
85   - @Param("edgeId") String edgeId,
86   - @Param("searchText") String searchText,
87   - @Param("idOffset") String idOffset,
88   - Pageable pageable);
89   -
90   - @Query("SELECT e FROM EntityViewEntity e WHERE e.tenantId = :tenantId " +
91   - "AND e.edgeId = :edgeId " +
92   - "AND e.type = :type " +
93   - "AND LOWER(e.searchText) LIKE LOWER(CONCAT(:searchText, '%')) " +
94   - "AND e.id > :idOffset ORDER BY e.id")
95   - List<EntityViewEntity> findByTenantIdAndEdgeIdAndType(@Param("tenantId") String tenantId,
96   - @Param("edgeId") String edgeId,
97   - @Param("type") String type,
98   - @Param("searchText") String searchText,
99   - @Param("idOffset") String idOffset,
100   - Pageable pageable);
101 79 }
... ...
... ... @@ -15,20 +15,29 @@
15 15 */
16 16 package org.thingsboard.server.dao.sql.entityview;
17 17
  18 +import com.google.common.util.concurrent.Futures;
18 19 import com.google.common.util.concurrent.ListenableFuture;
  20 +import com.google.common.util.concurrent.MoreExecutors;
  21 +import lombok.extern.slf4j.Slf4j;
19 22 import org.springframework.beans.factory.annotation.Autowired;
20 23 import org.springframework.data.domain.PageRequest;
21 24 import org.springframework.data.repository.CrudRepository;
22 25 import org.springframework.stereotype.Component;
  26 +import org.thingsboard.server.common.data.Device;
23 27 import org.thingsboard.server.common.data.EntitySubtype;
24 28 import org.thingsboard.server.common.data.EntityType;
25 29 import org.thingsboard.server.common.data.EntityView;
26 30 import org.thingsboard.server.common.data.UUIDConverter;
  31 +import org.thingsboard.server.common.data.id.EdgeId;
27 32 import org.thingsboard.server.common.data.id.TenantId;
28 33 import org.thingsboard.server.common.data.page.TextPageLink;
  34 +import org.thingsboard.server.common.data.page.TimePageLink;
  35 +import org.thingsboard.server.common.data.relation.EntityRelation;
  36 +import org.thingsboard.server.common.data.relation.RelationTypeGroup;
29 37 import org.thingsboard.server.dao.DaoUtil;
30 38 import org.thingsboard.server.dao.entityview.EntityViewDao;
31 39 import org.thingsboard.server.dao.model.sql.EntityViewEntity;
  40 +import org.thingsboard.server.dao.relation.RelationDao;
32 41 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
33 42 import org.thingsboard.server.dao.util.SqlDao;
34 43
... ... @@ -47,12 +56,16 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID_STR;
47 56 */
48 57 @Component
49 58 @SqlDao
  59 +@Slf4j
50 60 public class JpaEntityViewDao extends JpaAbstractSearchTextDao<EntityViewEntity, EntityView>
51 61 implements EntityViewDao {
52 62
53 63 @Autowired
54 64 private EntityViewRepository entityViewRepository;
55 65
  66 + @Autowired
  67 + private RelationDao relationDao;
  68 +
56 69 @Override
57 70 protected Class<EntityViewEntity> getEntityClass() {
58 71 return EntityViewEntity.class;
... ... @@ -140,30 +153,15 @@ public class JpaEntityViewDao extends JpaAbstractSearchTextDao<EntityViewEntity,
140 153 }
141 154
142 155 @Override
143   - public List<EntityView> findEntityViewsByTenantIdAndEdgeId(UUID tenantId,
144   - UUID edgeId,
145   - TextPageLink pageLink) {
146   - return DaoUtil.convertDataList(
147   - entityViewRepository.findByTenantIdAndEdgeId(
148   - fromTimeUUID(tenantId),
149   - fromTimeUUID(edgeId),
150   - Objects.toString(pageLink.getTextSearch(), ""),
151   - pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()),
152   - PageRequest.of(0, pageLink.getLimit())
153   - ));
154   - }
155   -
156   - @Override
157   - public List<EntityView> findEntityViewsByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink) {
158   - return DaoUtil.convertDataList(
159   - entityViewRepository.findByTenantIdAndEdgeIdAndType(
160   - fromTimeUUID(tenantId),
161   - fromTimeUUID(edgeId),
162   - type,
163   - Objects.toString(pageLink.getTextSearch(), ""),
164   - pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()),
165   - PageRequest.of(0, pageLink.getLimit())
166   - ));
  156 + public ListenableFuture<List<EntityView>> findEntityViewsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink) {
  157 + log.debug("Try to find entity views by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink);
  158 + ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(new TenantId(tenantId), new EdgeId(edgeId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE, EntityType.ENTITY_VIEW, pageLink);
  159 + return Futures.transformAsync(relations, input -> {
  160 + List<ListenableFuture<EntityView>> entityViewFutures = new ArrayList<>(input.size());
  161 + for (EntityRelation relation : input) {
  162 + entityViewFutures.add(findByIdAsync(new TenantId(tenantId), relation.getTo().getId()));
  163 + }
  164 + return Futures.successfulAsList(entityViewFutures);
  165 + }, MoreExecutors.directExecutor());
167 166 }
168   -
169 167 }
... ...
... ... @@ -42,7 +42,6 @@ CREATE TABLE IF NOT EXISTS asset (
42 42 id varchar(31) NOT NULL CONSTRAINT asset_pkey PRIMARY KEY,
43 43 additional_info varchar,
44 44 customer_id varchar(31),
45   - edge_id varchar(31),
46 45 name varchar(255),
47 46 label varchar(255),
48 47 search_text varchar(255),
... ... @@ -120,7 +119,6 @@ CREATE TABLE IF NOT EXISTS device (
120 119 id varchar(31) NOT NULL CONSTRAINT device_pkey PRIMARY KEY,
121 120 additional_info varchar,
122 121 customer_id varchar(31),
123   - edge_id varchar(31),
124 122 type varchar(255),
125 123 name varchar(255),
126 124 label varchar(255),
... ... @@ -247,7 +245,6 @@ CREATE TABLE IF NOT EXISTS entity_view (
247 245 entity_type varchar(255),
248 246 tenant_id varchar(31),
249 247 customer_id varchar(31),
250   - edge_id varchar(31),
251 248 type varchar(255),
252 249 name varchar(255),
253 250 keys varchar(10000000),
... ...
... ... @@ -42,7 +42,6 @@ CREATE TABLE IF NOT EXISTS asset (
42 42 id varchar(31) NOT NULL CONSTRAINT asset_pkey PRIMARY KEY,
43 43 additional_info varchar,
44 44 customer_id varchar(31),
45   - edge_id varchar(31),
46 45 name varchar(255),
47 46 label varchar(255),
48 47 search_text varchar(255),
... ... @@ -120,7 +119,6 @@ CREATE TABLE IF NOT EXISTS device (
120 119 id varchar(31) NOT NULL CONSTRAINT device_pkey PRIMARY KEY,
121 120 additional_info varchar,
122 121 customer_id varchar(31),
123   - edge_id varchar(31),
124 122 type varchar(255),
125 123 name varchar(255),
126 124 label varchar(255),
... ... @@ -247,7 +245,6 @@ CREATE TABLE IF NOT EXISTS entity_view (
247 245 entity_type varchar(255),
248 246 tenant_id varchar(31),
249 247 customer_id varchar(31),
250   - edge_id varchar(31),
251 248 type varchar(255),
252 249 name varchar(255),
253 250 keys varchar(10000000),
... ...
... ... @@ -18,7 +18,7 @@ export default angular.module('thingsboard.api.asset', [])
18 18 .name;
19 19
20 20 /*@ngInject*/
21   -function AssetService($http, $q, customerService, userService) {
  21 +function AssetService($http, $q, $filter, customerService, userService) {
22 22
23 23 var service = {
24 24 getAsset: getAsset,
... ... @@ -307,9 +307,9 @@ function AssetService($http, $q, customerService, userService) {
307 307 return deferred.promise;
308 308 }
309 309
310   - function unassignAssetFromEdge(assetId, ignoreErrors, config) {
  310 + function unassignAssetFromEdge(edgeId, assetId, ignoreErrors, config) {
311 311 var deferred = $q.defer();
312   - var url = '/api/edge/asset/' + assetId;
  312 + var url = '/api/edge/' + edgeId + '/asset/' + assetId;
313 313 if (!config) {
314 314 config = {};
315 315 }
... ... @@ -325,24 +325,20 @@ function AssetService($http, $q, customerService, userService) {
325 325 function getEdgeAssets(edgeId, pageLink, config, type) {
326 326 var deferred = $q.defer();
327 327 var url = '/api/edge/' + edgeId + '/assets?limit=' + pageLink.limit;
328   - if (angular.isDefined(pageLink.textSearch)) {
329   - url += '&textSearch=' + pageLink.textSearch;
330   - }
331 328 if (angular.isDefined(pageLink.idOffset)) {
332   - url += '&idOffset=' + pageLink.idOffset;
333   - }
334   - if (angular.isDefined(pageLink.textOffset)) {
335   - url += '&textOffset=' + pageLink.textOffset;
336   - }
337   - if (angular.isDefined(type) && type.length) {
338   - url += '&type=' + type;
  329 + url += '&offset=' + pageLink.idOffset;
339 330 }
340 331 $http.get(url, config).then(function success(response) {
  332 + if (pageLink.textSearch) {
  333 + response.data.data = $filter('filter')(response.data.data, {name: pageLink.textSearch});
  334 + }
  335 + if (angular.isDefined(type) && type.length) {
  336 + response.data.data = $filter('filter')(response.data.data, {type: type});
  337 + }
341 338 deferred.resolve(response.data);
342 339 }, function fail() {
343 340 deferred.reject();
344 341 });
345   -
346 342 return deferred.promise;
347 343 }
348 344 }
... ...
... ... @@ -20,7 +20,7 @@ export default angular.module('thingsboard.api.device', [thingsboardTypes])
20 20 .name;
21 21
22 22 /*@ngInject*/
23   -function DeviceService($http, $q, $window, userService, attributeService, customerService, types) {
  23 +function DeviceService($http, $q, $window, $filter, userService, attributeService, customerService, types) {
24 24
25 25 var service = {
26 26 assignDeviceToCustomer: assignDeviceToCustomer,
... ... @@ -373,9 +373,9 @@ function DeviceService($http, $q, $window, userService, attributeService, custom
373 373 return deferred.promise;
374 374 }
375 375
376   - function unassignDeviceFromEdge(deviceId) {
  376 + function unassignDeviceFromEdge(edgeId, deviceId) {
377 377 var deferred = $q.defer();
378   - var url = '/api/edge/device/' + deviceId;
  378 + var url = '/api/edge/' + edgeId + '/device/' + deviceId;
379 379 $http.delete(url).then(function success(response) {
380 380 deferred.resolve(response.data);
381 381 }, function fail() {
... ... @@ -387,25 +387,20 @@ function DeviceService($http, $q, $window, userService, attributeService, custom
387 387 function getEdgeDevices(edgeId, pageLink, config, type) {
388 388 var deferred = $q.defer();
389 389 var url = '/api/edge/' + edgeId + '/devices?limit=' + pageLink.limit;
390   - if (angular.isDefined(pageLink.textSearch)) {
391   - url += '&textSearch=' + pageLink.textSearch;
392   - }
393 390 if (angular.isDefined(pageLink.idOffset)) {
394   - url += '&idOffset=' + pageLink.idOffset;
395   - }
396   - if (angular.isDefined(pageLink.textOffset)) {
397   - url += '&textOffset=' + pageLink.textOffset;
398   - }
399   - if (angular.isDefined(type) && type.length) {
400   - url += '&type=' + type;
  391 + url += '&offset=' + pageLink.idOffset;
401 392 }
402 393 $http.get(url, config).then(function success(response) {
  394 + if (pageLink.textSearch) {
  395 + response.data.data = $filter('filter')(response.data.data, {name: pageLink.textSearch});
  396 + }
  397 + if (angular.isDefined(type) && type.length) {
  398 + response.data.data = $filter('filter')(response.data.data, {type: type});
  399 + }
403 400 deferred.resolve(response.data);
404 401 }, function fail() {
405 402 deferred.reject();
406 403 });
407   -
408 404 return deferred.promise;
409 405 }
410   -
411 406 }
... ...
... ... @@ -20,7 +20,7 @@ export default angular.module('thingsboard.api.entityView', [thingsboardTypes])
20 20 .name;
21 21
22 22 /*@ngInject*/
23   -function EntityViewService($http, $q, $window, userService, attributeService, customerService, types) {
  23 +function EntityViewService($http, $q, $window, $filter, userService, attributeService, customerService, types) {
24 24
25 25 var service = {
26 26 assignEntityViewToCustomer: assignEntityViewToCustomer,
... ... @@ -234,9 +234,9 @@ function EntityViewService($http, $q, $window, userService, attributeService, cu
234 234 return deferred.promise;
235 235 }
236 236
237   - function unassignEntityViewFromEdge(entityViewId) {
  237 + function unassignEntityViewFromEdge(edgeId, entityViewId) {
238 238 var deferred = $q.defer();
239   - var url = '/api/edge/entityView/' + entityViewId;
  239 + var url = '/api/edge/' + edgeId + '/entityView/' + entityViewId;
240 240 $http.delete(url).then(function success(response) {
241 241 deferred.resolve(response.data);
242 242 }, function fail() {
... ... @@ -248,24 +248,20 @@ function EntityViewService($http, $q, $window, userService, attributeService, cu
248 248 function getEdgeEntityViews(edgeId, pageLink, config, type) {
249 249 var deferred = $q.defer();
250 250 var url = '/api/edge/' + edgeId + '/entityViews?limit=' + pageLink.limit;
251   - if (angular.isDefined(pageLink.textSearch)) {
252   - url += '&textSearch=' + pageLink.textSearch;
253   - }
254 251 if (angular.isDefined(pageLink.idOffset)) {
255   - url += '&idOffset=' + pageLink.idOffset;
256   - }
257   - if (angular.isDefined(pageLink.textOffset)) {
258   - url += '&textOffset=' + pageLink.textOffset;
259   - }
260   - if (angular.isDefined(type) && type.length) {
261   - url += '&type=' + type;
  252 + url += '&offset=' + pageLink.idOffset;
262 253 }
263 254 $http.get(url, config).then(function success(response) {
  255 + if (pageLink.textSearch) {
  256 + response.data.data = $filter('filter')(response.data.data, {name: pageLink.textSearch});
  257 + }
  258 + if (angular.isDefined(type) && type.length) {
  259 + response.data.data = $filter('filter')(response.data.data, {type: type});
  260 + }
264 261 deferred.resolve(response.data);
265 262 }, function fail() {
266 263 deferred.reject();
267 264 });
268   -
269 265 return deferred.promise;
270 266 }
271 267 }
... ...
... ... @@ -327,7 +327,7 @@ export function AssetController($rootScope, userService, assetService, customerS
327 327 return assetService.getEdgeAssets(edgeId, pageLink, null, assetType);
328 328 };
329 329 deleteAssetFunction = function (assetId) {
330   - return assetService.unassignAssetFromEdge(assetId);
  330 + return assetService.unassignAssetFromEdge(edgeId, assetId);
331 331 };
332 332 refreshAssetsParamsFunction = function () {
333 333 return {"edgeId": edgeId, "topIndex": vm.topIndex};
... ... @@ -630,7 +630,7 @@ export function AssetController($rootScope, userService, assetService, customerS
630 630 .cancel($translate.instant('action.no'))
631 631 .ok($translate.instant('action.yes'));
632 632 $mdDialog.show(confirm).then(function () {
633   - assetService.unassignAssetFromEdge(asset.id.id).then(function success() {
  633 + assetService.unassignAssetFromEdge(edgeId, asset.id.id).then(function success() {
634 634 vm.grid.refreshList();
635 635 });
636 636 });
... ... @@ -639,15 +639,15 @@ export function AssetController($rootScope, userService, assetService, customerS
639 639 function unassignAssetsFromEdge($event, items) {
640 640 var confirm = $mdDialog.confirm()
641 641 .targetEvent($event)
642   - .title($translate.instant('asset.unassign-assets-title', {count: items.selectedCount}, 'messageformat'))
643   - .htmlContent($translate.instant('asset.unassign-assets-text'))
644   - .ariaLabel($translate.instant('asset.unassign-asset'))
  642 + .title($translate.instant('asset.unassign-assets-from-edge-title', {count: items.selectedCount}, 'messageformat'))
  643 + .htmlContent($translate.instant('asset.unassign-assets-from-edge-text'))
  644 + .ariaLabel($translate.instant('asset.unassign-asset-from-edge'))
645 645 .cancel($translate.instant('action.no'))
646 646 .ok($translate.instant('action.yes'));
647 647 $mdDialog.show(confirm).then(function () {
648 648 var tasks = [];
649 649 for (var id in items.selections) {
650   - tasks.push(assetService.unassignAssetFromEdge(id));
  650 + tasks.push(assetService.unassignAssetFromEdge(edgeId, id));
651 651 }
652 652 $q.all(tasks).then(function () {
653 653 vm.grid.refreshList();
... ...
... ... @@ -360,7 +360,7 @@ export function DeviceController($rootScope, userService, deviceService, custome
360 360 return deviceService.getEdgeDevices(edgeId, pageLink, null, deviceType);
361 361 };
362 362 deleteDeviceFunction = function (deviceId) {
363   - return deviceService.unassignDeviceFromEdge(deviceId);
  363 + return deviceService.unassignDeviceFromEdge(edgeId, deviceId);
364 364 };
365 365 refreshDevicesParamsFunction = function () {
366 366 return {"edgeId": edgeId, "topIndex": vm.topIndex};
... ... @@ -679,7 +679,7 @@ export function DeviceController($rootScope, userService, deviceService, custome
679 679 .cancel($translate.instant('action.no'))
680 680 .ok($translate.instant('action.yes'));
681 681 $mdDialog.show(confirm).then(function () {
682   - deviceService.unassignDeviceFromEdge(device.id.id).then(function success() {
  682 + deviceService.unassignDeviceFromEdge(edgeId, device.id.id).then(function success() {
683 683 vm.grid.refreshList();
684 684 });
685 685 });
... ... @@ -688,15 +688,15 @@ export function DeviceController($rootScope, userService, deviceService, custome
688 688 function unassignDevicesFromEdge($event, items) {
689 689 var confirm = $mdDialog.confirm()
690 690 .targetEvent($event)
691   - .title($translate.instant('device.unassign-devices-title', {count: items.selectedCount}, 'messageformat'))
692   - .htmlContent($translate.instant('device.unassign-devices-text'))
693   - .ariaLabel($translate.instant('device.unassign-device'))
  691 + .title($translate.instant('device.unassign-devices-from-edge-title', {count: items.selectedCount}, 'messageformat'))
  692 + .htmlContent($translate.instant('device.unassign-devices-from-edge-text'))
  693 + .ariaLabel($translate.instant('device.unassign-device-from-edge'))
694 694 .cancel($translate.instant('action.no'))
695 695 .ok($translate.instant('action.yes'));
696 696 $mdDialog.show(confirm).then(function () {
697 697 var tasks = [];
698 698 for (var id in items.selections) {
699   - tasks.push(deviceService.unassignDeviceFromEdge(id));
  699 + tasks.push(deviceService.unassignDeviceFromEdge(edgeId, id));
700 700 }
701 701 $q.all(tasks).then(function () {
702 702 vm.grid.refreshList();
... ...
... ... @@ -288,7 +288,7 @@ export function EntityViewController($rootScope, userService, entityViewService,
288 288 return entityViewService.getEdgeEntityViews(edgeId, pageLink, null, entityViewType);
289 289 };
290 290 deleteEntityViewFunction = function (entityViewId) {
291   - return entityViewService.unassignEntityViewFromEdge(entityViewId);
  291 + return entityViewService.unassignEntityViewFromEdge(edgeId, entityViewId);
292 292 };
293 293 refreshEntityViewsParamsFunction = function () {
294 294 return {"edgeId": edgeId, "topIndex": vm.topIndex};
... ... @@ -300,10 +300,7 @@ export function EntityViewController($rootScope, userService, entityViewService,
300 300 },
301 301 name: function() { return $translate.instant('action.unassign') },
302 302 details: function() { return $translate.instant('entity-view.unassign-from-edge') },
303   - icon: "assignment_return",
304   - isEnabled: function(entityView) {
305   - return entityView && entityView.edgeId && entityView.edgeId.id !== types.id.nullUid;
306   - }
  303 + icon: "assignment_return"
307 304 }
308 305 );
309 306
... ... @@ -314,7 +311,7 @@ export function EntityViewController($rootScope, userService, entityViewService,
314 311 },
315 312 name: function() { return $translate.instant('entity-view.unassign-entity-views') },
316 313 details: function(selectedCount) {
317   - return $translate.instant('entity-view.unassign-entity-views-action-title', {count: selectedCount}, "messageformat");
  314 + return $translate.instant('entity-view.unassign-entity-views-from-edge-action-title', {count: selectedCount}, "messageformat");
318 315 },
319 316 icon: "assignment_return"
320 317 }
... ... @@ -581,15 +578,15 @@ export function EntityViewController($rootScope, userService, entityViewService,
581 578 function unassignEntityViewsFromEdge($event, items) {
582 579 var confirm = $mdDialog.confirm()
583 580 .targetEvent($event)
584   - .title($translate.instant('entity-view.unassign-entity-views-title', {count: items.selectedCount}, 'messageformat'))
585   - .htmlContent($translate.instant('entity-view.unassign-entity-views-text'))
586   - .ariaLabel($translate.instant('entity-view.unassign-entity-view'))
  581 + .title($translate.instant('entity-view.unassign-entity-views-from-edge-title', {count: items.selectedCount}, 'messageformat'))
  582 + .htmlContent($translate.instant('entity-view.unassign-entity-views-from-edge-text'))
  583 + .ariaLabel($translate.instant('entity-view.unassign-entity-view-from-edge'))
587 584 .cancel($translate.instant('action.no'))
588 585 .ok($translate.instant('action.yes'));
589 586 $mdDialog.show(confirm).then(function () {
590 587 var tasks = [];
591 588 for (var id in items.selections) {
592   - tasks.push(entityViewService.unassignEntityViewFromEdge(id));
  589 + tasks.push(entityViewService.unassignEntityViewFromEdge(edgeId, id));
593 590 }
594 591 $q.all(tasks).then(function () {
595 592 vm.grid.refreshList();
... ... @@ -612,7 +609,7 @@ export function EntityViewController($rootScope, userService, entityViewService,
612 609 .cancel($translate.instant('action.no'))
613 610 .ok($translate.instant('action.yes'));
614 611 $mdDialog.show(confirm).then(function () {
615   - entityViewService.unassignEntityViewFromEdge(entityView.id.id).then(function success() {
  612 + entityViewService.unassignEntityViewFromEdge(edgeId, entityView.id.id).then(function success() {
616 613 vm.grid.refreshList();
617 614 });
618 615 });
... ...
... ... @@ -291,9 +291,12 @@
291 291 "unassign-from-edge": "Unassign from edge",
292 292 "assign-to-edge": "Assign to edge",
293 293 "assign-to-edge-text": "Please select the edge to assign the asset(s)",
  294 + "unassign-asset-from-edge": "Unassign asset",
294 295 "unassign-asset-from-edge-title": "Are you sure you want to unassign the asset '{{assetName}}'?",
295 296 "unassign-asset-from-edge-text": "After the confirmation the asset will be unassigned and won't be accessible by the edge.",
296   - "unassign-assets-from-edge-action-title": "Unassign { count, plural, 1 {1 asset} other {# assets} } from edge"
  297 + "unassign-assets-from-edge-action-title": "Unassign { count, plural, 1 {1 asset} other {# assets} } from edge",
  298 + "unassign-assets-from-edge-title": "Are you sure you want to unassign { count, plural, 1 {1 asset} other {# assets} }?",
  299 + "unassign-assets-from-edge-text": "After the confirmation all selected assets will be unassigned and won't be accessible by the edge."
297 300 },
298 301 "attribute": {
299 302 "attributes": "Attributes",
... ... @@ -748,7 +751,10 @@
748 751 "assign-to-edge-text": "Please select the edge to assign the device(s)",
749 752 "unassign-device-from-edge-title": "Are you sure you want to unassign the device '{{deviceName}}'?",
750 753 "unassign-device-from-edge-text": "After the confirmation the device will be unassigned and won't be accessible by the edge.",
751   - "unassign-devices-from-edge-action-title": "Unassign { count, plural, 1 {1 device} other {# devices} } from edge"
  754 + "unassign-devices-from-edge-action-title": "Unassign { count, plural, 1 {1 device} other {# devices} } from edge",
  755 + "unassign-device-from-edge": "Unassign device",
  756 + "unassign-devices-from-edge-title": "Are you sure you want to unassign { count, plural, 1 {1 device} other {# devices} }?",
  757 + "unassign-devices-from-edge-text": "After the confirmation all selected devices will be unassigned and won't be accessible by the edge."
752 758 },
753 759 "dialog": {
754 760 "close": "Close dialog"
... ... @@ -1054,7 +1060,10 @@
1054 1060 "assign-to-edge-text": "Please select the edge to assign the entity view(s)",
1055 1061 "unassign-entity-view-from-edge-title": "Are you sure you want to unassign the entity view '{{entityViewName}}'?",
1056 1062 "unassign-entity-view-from-edge-text": "After the confirmation the entity view will be unassigned and won't be accessible by the edge.",
1057   - "unassign-entity-views-from-edge-action-title": "Unassign { count, plural, 1 {1 entity view} other {# entity views} } from edge"
  1063 + "unassign-entity-views-from-edge-action-title": "Unassign { count, plural, 1 {1 entity view} other {# entity views} } from edge",
  1064 + "unassign-entity-view-from-edge": "Unassign entity view",
  1065 + "unassign-entity-views-from-edge-title": "Are you sure you want to unassign { count, plural, 1 {1 entity view} other {# entity views} }?",
  1066 + "unassign-entity-views-from-edge-text": "After the confirmation all selected entity views will be unassigned and won't be accessible by the edge."
1058 1067 },
1059 1068 "event": {
1060 1069 "event-type": "Event type",
... ... @@ -1580,7 +1589,7 @@
1580 1589 "invalid-rulechain-type-error": "Unable to import rule chain: Invalid rule chain type. Expected type is {{expectedRuleChainType}}.",
1581 1590 "set-default-edge": "Make edge rule chain default",
1582 1591 "set-default-edge-title": "Are you sure you want to make the edge rule chain '{{ruleChainName}}' default?",
1583   - "set-default-edge-text": "After the confirmation the edge rule chain will be added to default list and handle all incoming transport messages.",
  1592 + "set-default-edge-text": "After the confirmation the edge rule chain will be added to default list and assigned to newly created edge(s).",
1584 1593 "remove-default-edge": "Remove edge rule chain from defaults",
1585 1594 "remove-default-edge-title": "Are you sure you want to remove the edge rule chain '{{ruleChainName}}' from default list?",
1586 1595 "remove-default-edge-text": "After the confirmation the edge rule chain will stop handling all incoming transport messages."
... ...