diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java index d50c25af74..1a0d600d7b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java @@ -40,6 +40,8 @@ import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.page.TimePageData; +import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.queue.util.TbCoreComponent; @@ -51,6 +53,8 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; +import static org.thingsboard.server.controller.EdgeController.EDGE_ID; + @RestController @TbCoreComponent @RequestMapping("/api") @@ -336,9 +340,9 @@ public class AssetController extends BaseController { @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/asset/{assetId}", method = RequestMethod.POST) @ResponseBody - public Asset assignAssetToEdge(@PathVariable("edgeId") String strEdgeId, + public Asset assignAssetToEdge(@PathVariable(EDGE_ID) String strEdgeId, @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException { - checkParameter("edgeId", strEdgeId); + checkParameter(EDGE_ID, strEdgeId); checkParameter(ASSET_ID, strAssetId); try { EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); @@ -365,20 +369,20 @@ public class AssetController extends BaseController { } @PreAuthorize("hasAuthority('TENANT_ADMIN')") - @RequestMapping(value = "/edge/asset/{assetId}", method = RequestMethod.DELETE) + @RequestMapping(value = "/edge/{edgeId}/asset/{assetId}", method = RequestMethod.DELETE) @ResponseBody - public Asset unassignAssetFromEdge(@PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException { + public Asset unassignAssetFromEdge(@PathVariable(EDGE_ID) String strEdgeId, + @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException { + checkParameter(EDGE_ID, strEdgeId); checkParameter(ASSET_ID, strAssetId); try { + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); + Edge edge = checkEdgeId(edgeId, Operation.READ); + AssetId assetId = new AssetId(toUUID(strAssetId)); Asset asset = checkAssetId(assetId, Operation.UNASSIGN_FROM_EDGE); - if (asset.getEdgeId() == null || asset.getEdgeId().getId().equals(ModelConstants.NULL_UUID)) { - throw new IncorrectParameterException("Asset isn't assigned to any edge!"); - } - Edge edge = checkEdgeId(asset.getEdgeId(), Operation.READ); - - Asset savedAsset = checkNotNull(assetService.unassignAssetFromEdge(getTenantId(), assetId)); + Asset savedAsset = checkNotNull(assetService.unassignAssetFromEdge(getTenantId(), assetId, edgeId)); logEntityAction(assetId, asset, asset.getCustomerId(), @@ -398,24 +402,20 @@ public class AssetController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/assets", params = {"limit"}, method = RequestMethod.GET) @ResponseBody - public TextPageData getEdgeAssets( - @PathVariable("edgeId") String strEdgeId, + public TimePageData getEdgeAssets( + @PathVariable(EDGE_ID) String strEdgeId, @RequestParam int limit, - @RequestParam(required = false) String type, - @RequestParam(required = false) String textSearch, - @RequestParam(required = false) String idOffset, - @RequestParam(required = false) String textOffset) throws ThingsboardException { - checkParameter("edgeId", strEdgeId); + @RequestParam(required = false) Long startTime, + @RequestParam(required = false) Long endTime, + @RequestParam(required = false, defaultValue = "false") boolean ascOrder, + @RequestParam(required = false) String offset) throws ThingsboardException { + checkParameter(EDGE_ID, strEdgeId); try { TenantId tenantId = getCurrentUser().getTenantId(); EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); checkEdgeId(edgeId, Operation.READ); - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); - if (type != null && type.trim().length()>0) { - return checkNotNull(assetService.findAssetsByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink)); - } else { - return checkNotNull(assetService.findAssetsByTenantIdAndEdgeId(tenantId, edgeId, pageLink)); - } + TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); + return checkNotNull(assetService.findAssetsByTenantIdAndEdgeId(tenantId, edgeId, pageLink).get()); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index fc38153425..8fc4202b76 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -49,6 +49,9 @@ import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.page.TimePageData; +import org.thingsboard.server.common.data.page.TimePageLink; +import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.dao.device.claim.ClaimResponse; import org.thingsboard.server.dao.device.claim.ClaimResult; @@ -519,19 +522,20 @@ public class DeviceController extends BaseController { } @PreAuthorize("hasAuthority('TENANT_ADMIN')") - @RequestMapping(value = "/edge/device/{deviceId}", method = RequestMethod.DELETE) + @RequestMapping(value = "/edge/{edgeId}/device/{deviceId}", method = RequestMethod.DELETE) @ResponseBody - public Device unassignDeviceFromEdge(@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException { + public Device unassignDeviceFromEdge(@PathVariable(EDGE_ID) String strEdgeId, + @PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException { + checkParameter(EDGE_ID, strEdgeId); checkParameter(DEVICE_ID, strDeviceId); try { + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); + Edge edge = checkEdgeId(edgeId, Operation.READ); + DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); Device device = checkDeviceId(deviceId, Operation.UNASSIGN_FROM_EDGE); - if (device.getEdgeId() == null || device.getEdgeId().getId().equals(ModelConstants.NULL_UUID)) { - throw new IncorrectParameterException("Device isn't assigned to any edge!"); - } - Edge edge = checkEdgeId(device.getEdgeId(), Operation.READ); - Device savedDevice = checkNotNull(deviceService.unassignDeviceFromEdge(getCurrentUser().getTenantId(), deviceId)); + Device savedDevice = checkNotNull(deviceService.unassignDeviceFromEdge(getCurrentUser().getTenantId(), deviceId, edgeId)); logEntityAction(deviceId, device, device.getCustomerId(), @@ -549,24 +553,20 @@ public class DeviceController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/devices", params = {"limit"}, method = RequestMethod.GET) @ResponseBody - public TextPageData getEdgeDevices( - @PathVariable("edgeId") String strEdgeId, + public TimePageData getEdgeDevices( + @PathVariable(EDGE_ID) String strEdgeId, @RequestParam int limit, - @RequestParam(required = false) String type, - @RequestParam(required = false) String textSearch, - @RequestParam(required = false) String idOffset, - @RequestParam(required = false) String textOffset) throws ThingsboardException { - checkParameter("edgeId", strEdgeId); + @RequestParam(required = false) Long startTime, + @RequestParam(required = false) Long endTime, + @RequestParam(required = false, defaultValue = "false") boolean ascOrder, + @RequestParam(required = false) String offset) throws ThingsboardException { + checkParameter(EDGE_ID, strEdgeId); try { TenantId tenantId = getCurrentUser().getTenantId(); EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); checkEdgeId(edgeId, Operation.READ); - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); - if (type != null && type.trim().length()>0) { - return checkNotNull(deviceService.findDevicesByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink)); - } else { - return checkNotNull(deviceService.findDevicesByTenantIdAndEdgeId(tenantId, edgeId, pageLink)); - } + TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); + return checkNotNull(deviceService.findDevicesByTenantIdAndEdgeId(tenantId, edgeId, pageLink).get()); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java index 27dfb64189..db4e8f86e7 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java @@ -48,6 +48,8 @@ import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.page.TimePageData; +import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.queue.util.TbCoreComponent; @@ -400,18 +402,20 @@ public class EntityViewController extends BaseController { } @PreAuthorize("hasAuthority('TENANT_ADMIN')") - @RequestMapping(value = "/edge/entityView/{entityViewId}", method = RequestMethod.DELETE) + @RequestMapping(value = "/edge/{edgeId}/entityView/{entityViewId}", method = RequestMethod.DELETE) @ResponseBody - public EntityView unassignEntityViewFromEdge(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { + public EntityView unassignEntityViewFromEdge(@PathVariable(EDGE_ID) String strEdgeId, + @PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { + checkParameter(EDGE_ID, strEdgeId); checkParameter(ENTITY_VIEW_ID, strEntityViewId); try { + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); + Edge edge = checkEdgeId(edgeId, Operation.READ); + EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); EntityView entityView = checkEntityViewId(entityViewId, Operation.UNASSIGN_FROM_EDGE); - if (entityView.getEdgeId() == null || entityView.getEdgeId().getId().equals(ModelConstants.NULL_UUID)) { - throw new IncorrectParameterException("Entity View isn't assigned to any edge!"); - } - Edge edge = checkEdgeId(entityView.getEdgeId(), Operation.READ); - EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromEdge(getTenantId(), entityViewId)); + + EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromEdge(getTenantId(), entityViewId, edgeId)); logEntityAction(entityViewId, entityView, entityView.getCustomerId(), ActionType.UNASSIGNED_FROM_EDGE, null, strEntityViewId, edge.getId().toString(), edge.getName()); @@ -428,24 +432,20 @@ public class EntityViewController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/entityViews", params = {"limit"}, method = RequestMethod.GET) @ResponseBody - public TextPageData getEdgeEntityViews( - @PathVariable("edgeId") String strEdgeId, + public TimePageData getEdgeEntityViews( + @PathVariable(EDGE_ID) String strEdgeId, @RequestParam int limit, - @RequestParam(required = false) String type, - @RequestParam(required = false) String textSearch, - @RequestParam(required = false) String idOffset, - @RequestParam(required = false) String textOffset) throws ThingsboardException { - checkParameter("edgeId", strEdgeId); + @RequestParam(required = false) Long startTime, + @RequestParam(required = false) Long endTime, + @RequestParam(required = false, defaultValue = "false") boolean ascOrder, + @RequestParam(required = false) String offset) throws ThingsboardException { + checkParameter(EDGE_ID, strEdgeId); try { TenantId tenantId = getCurrentUser().getTenantId(); EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); checkEdgeId(edgeId, Operation.READ); - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); - if (type != null && type.trim().length()>0) { - return checkNotNull(entityViewService.findEntityViewsByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink)); - } else { - return checkNotNull(entityViewService.findEntityViewsByTenantIdAndEdgeId(tenantId, edgeId, pageLink)); - } + TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); + return checkNotNull(entityViewService.findEntityViewsByTenantIdAndEdgeId(tenantId, edgeId, pageLink).get()); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java index f701b6506b..c1a94d99d6 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java @@ -554,7 +554,7 @@ public final class EdgeGrpcSession implements Closeable { case ENTITY_DELETED_RPC_MESSAGE: Device device = ctx.getDeviceService().findDeviceByTenantIdAndName(edge.getTenantId(), deviceName); if (device != null) { - ctx.getDeviceService().unassignDeviceFromEdge(edge.getTenantId(), device.getId()); + ctx.getDeviceService().unassignDeviceFromEdge(edge.getTenantId(), device.getId(), edge.getId()); } break; } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/init/DefaultInitEdgeService.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/init/DefaultInitEdgeService.java index 848b67be84..192fb8395b 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/init/DefaultInitEdgeService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/init/DefaultInitEdgeService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.service.edge.rpc.init; +import com.google.common.util.concurrent.Futures; import io.grpc.stub.StreamObserver; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -54,6 +55,7 @@ import org.thingsboard.server.service.edge.rpc.constructor.EntityViewUpdateMsgCo import org.thingsboard.server.service.edge.rpc.constructor.RuleChainUpdateMsgConstructor; import java.util.UUID; +import java.util.concurrent.Future; @Service @Slf4j @@ -100,10 +102,10 @@ public class DefaultInitEdgeService implements InitEdgeService { private void initDevices(Edge edge, StreamObserver outputStream) { try { - TextPageLink pageLink = new TextPageLink(100); - TextPageData pageData; + TimePageLink pageLink = new TimePageLink(100); + TimePageData pageData; do { - pageData = deviceService.findDevicesByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink); + pageData = deviceService.findDevicesByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink).get(); if (!pageData.getData().isEmpty()) { log.trace("[{}] [{}] device(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); for (Device device : pageData.getData()) { @@ -130,10 +132,10 @@ public class DefaultInitEdgeService implements InitEdgeService { private void initAssets(Edge edge, StreamObserver outputStream) { try { - TextPageLink pageLink = new TextPageLink(100); - TextPageData pageData; + TimePageLink pageLink = new TimePageLink(100); + TimePageData pageData; do { - pageData = assetService.findAssetsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink); + pageData = assetService.findAssetsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink).get(); if (!pageData.getData().isEmpty()) { log.trace("[{}] [{}] asset(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); for (Asset asset : pageData.getData()) { @@ -160,10 +162,10 @@ public class DefaultInitEdgeService implements InitEdgeService { private void initEntityViews(Edge edge, StreamObserver outputStream) { try { - TextPageLink pageLink = new TextPageLink(100); - TextPageData pageData; + TimePageLink pageLink = new TimePageLink(100); + TimePageData pageData; do { - pageData = entityViewService.findEntityViewsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink); + pageData = entityViewService.findEntityViewsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink).get(); if (!pageData.getData().isEmpty()) { log.trace("[{}] [{}] entity view(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); for (EntityView entityView : pageData.getData()) { diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java index 5227efcfa3..29d698d0a4 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java @@ -311,18 +311,6 @@ public class CassandraDatabaseUpgradeService extends AbstractCassandraDatabaseUp schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.6.0", SCHEMA_UPDATE_CQL); loadCql(schemaUpdateFile); - try { - cluster.getSession().execute("alter table asset add edge_id text"); - Thread.sleep(2500); - } catch (InvalidQueryException e) {} - try { - cluster.getSession().execute("alter table device add edge_id text"); - Thread.sleep(2500); - } catch (InvalidQueryException e) {} - try { - cluster.getSession().execute("alter table entity_view add edge_id text"); - Thread.sleep(2500); - } catch (InvalidQueryException e) {} try { cluster.getSession().execute("alter table rule_chain add type text"); Thread.sleep(2500); diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index c9966d0cbb..f9c5e53fd5 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -238,15 +238,6 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService log.info("Updating schema ..."); schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.6.0", SCHEMA_UPDATE_SQL); loadSql(schemaUpdateFile, conn); - try { - conn.createStatement().execute("ALTER TABLE asset ADD edge_id varchar(31)"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script - } catch (Exception e) {} - try { - conn.createStatement().execute("ALTER TABLE device ADD edge_id varchar(31)"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script - } catch (Exception e) {} - try { - conn.createStatement().execute("ALTER TABLE entity_view ADD edge_id varchar(31)"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script - } catch (Exception e) {} try { conn.createStatement().execute("ALTER TABLE rule_chain ADD type varchar(255) DEFAULT 'SYSTEM'"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script } catch (Exception e) {} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetService.java index 13a3799cf2..e0db26b718 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetService.java @@ -25,6 +25,8 @@ import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.page.TimePageData; +import org.thingsboard.server.common.data.page.TimePageLink; import java.util.List; import java.util.Optional; @@ -67,9 +69,7 @@ public interface AssetService { Asset assignAssetToEdge(TenantId tenantId, AssetId assetId, EdgeId edgeId); - Asset unassignAssetFromEdge(TenantId tenantId, AssetId assetId); + Asset unassignAssetFromEdge(TenantId tenantId, AssetId assetId, EdgeId edgeId); - TextPageData findAssetsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TextPageLink pageLink); - - TextPageData findAssetsByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink); + ListenableFuture> findAssetsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java index 3bd47fbd68..4e3099e25b 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java @@ -25,11 +25,13 @@ import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.page.TimePageData; +import org.thingsboard.server.common.data.page.TimePageLink; import java.util.List; public interface DeviceService { - + Device findDeviceById(TenantId tenantId, DeviceId deviceId); ListenableFuture findDeviceByIdAsync(TenantId tenantId, DeviceId deviceId); @@ -68,10 +70,7 @@ public interface DeviceService { Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId); - Device unassignDeviceFromEdge(TenantId tenantId, DeviceId deviceId); - - TextPageData findDevicesByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TextPageLink pageLink); - - TextPageData findDevicesByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink); + Device unassignDeviceFromEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId); + ListenableFuture> findDevicesByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java index 04b096f4b2..6061a448e6 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java @@ -26,6 +26,8 @@ import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.page.TimePageData; +import org.thingsboard.server.common.data.page.TimePageLink; import java.util.List; @@ -68,11 +70,7 @@ public interface EntityViewService { EntityView assignEntityViewToEdge(TenantId tenantId, EntityViewId entityViewId, EdgeId edgeId); - EntityView unassignEntityViewFromEdge(TenantId tenantId, EntityViewId entityViewId); - - TextPageData findEntityViewsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TextPageLink pageLink); - - TextPageData findEntityViewsByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink); - + EntityView unassignEntityViewFromEdge(TenantId tenantId, EntityViewId entityViewId, EdgeId edgeId); + ListenableFuture> findEntityViewsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Device.java b/common/data/src/main/java/org/thingsboard/server/common/data/Device.java index 201bbc8b07..cd617ec345 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Device.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Device.java @@ -18,7 +18,6 @@ package org.thingsboard.server.common.data; import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; -import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; @EqualsAndHashCode(callSuper = true) @@ -28,7 +27,6 @@ public class Device extends SearchTextBasedWithAdditionalInfo implemen private TenantId tenantId; private CustomerId customerId; - private EdgeId edgeId; private String name; private String type; private String label; @@ -48,7 +46,6 @@ public class Device extends SearchTextBasedWithAdditionalInfo implemen this.name = device.getName(); this.type = device.getType(); this.label = device.getLabel(); - this.edgeId = device.getEdgeId(); } public TenantId getTenantId() { @@ -67,14 +64,6 @@ public class Device extends SearchTextBasedWithAdditionalInfo implemen this.customerId = customerId; } - public EdgeId getEdgeId() { - return edgeId; - } - - public void setEdgeId(EdgeId edgeId) { - this.edgeId = edgeId; - } - @Override public String getName() { return name; @@ -112,8 +101,6 @@ public class Device extends SearchTextBasedWithAdditionalInfo implemen builder.append(tenantId); builder.append(", customerId="); builder.append(customerId); - builder.append(", edgeId="); - builder.append(edgeId); builder.append(", name="); builder.append(name); builder.append(", type="); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java b/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java index 157a5c884e..4c7e69d79e 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java @@ -19,7 +19,6 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.id.CustomerId; -import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; @@ -40,7 +39,6 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo private EntityId entityId; private TenantId tenantId; private CustomerId customerId; - private EdgeId edgeId; private String name; private String type; private TelemetryEntityView keys; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java b/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java index e0dc5dc90c..e0f587dda4 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java @@ -15,13 +15,10 @@ */ package org.thingsboard.server.common.data.asset; -import com.fasterxml.jackson.databind.JsonNode; import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.*; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; -import org.thingsboard.server.common.data.id.EdgeId; -import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; @EqualsAndHashCode(callSuper = true) @@ -34,7 +31,6 @@ public class Asset extends SearchTextBasedWithAdditionalInfo implements private String name; private String type; private String label; - private EdgeId edgeId; public Asset() { super(); @@ -51,7 +47,6 @@ public class Asset extends SearchTextBasedWithAdditionalInfo implements this.name = asset.getName(); this.type = asset.getType(); this.label = asset.getLabel(); - this.edgeId = asset.getEdgeId(); } public TenantId getTenantId() { @@ -70,14 +65,6 @@ public class Asset extends SearchTextBasedWithAdditionalInfo implements this.customerId = customerId; } - public EdgeId getEdgeId() { - return edgeId; - } - - public void setEdgeId(EdgeId edgeId) { - this.edgeId = edgeId; - } - @Override public String getName() { return name; @@ -115,8 +102,6 @@ public class Asset extends SearchTextBasedWithAdditionalInfo implements builder.append(tenantId); builder.append(", customerId="); builder.append(customerId); - builder.append(", edgeId="); - builder.append(edgeId); builder.append(", name="); builder.append(name); builder.append(", type="); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index 41f8a2b630..118b8d47fd 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -341,16 +341,6 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ } } - private void deleteRelation(TenantId tenantId, EntityRelation alarmRelation) { - log.debug("Deleting Alarm relation: {}", alarmRelation); - relationService.deleteRelation(tenantId, alarmRelation); - } - - private void createRelation(TenantId tenantId, EntityRelation alarmRelation) { - log.debug("Creating Alarm relation: {}", alarmRelation); - relationService.saveRelation(tenantId, alarmRelation); - } - private Alarm merge(Alarm existing, Alarm alarm) { if (alarm.getStartTs() > existing.getEndTs()) { existing.setEndTs(alarm.getStartTs()); @@ -395,7 +385,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ } } - private void createAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus status, boolean createAnyRelation) { + private void createAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus status, boolean createAnyRelation) throws ExecutionException, InterruptedException { if (createAnyRelation) { createRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + AlarmSearchStatus.ANY.name(), RelationTypeGroup.ALARM)); } @@ -404,13 +394,13 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ createRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getAckSearchStatus().name(), RelationTypeGroup.ALARM)); } - private void deleteAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus status) { + private void deleteAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus status) throws ExecutionException, InterruptedException { deleteRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.name(), RelationTypeGroup.ALARM)); deleteRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getClearSearchStatus().name(), RelationTypeGroup.ALARM)); deleteRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getAckSearchStatus().name(), RelationTypeGroup.ALARM)); } - private void updateAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus oldStatus, AlarmStatus newStatus) { + private void updateAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus oldStatus, AlarmStatus newStatus) throws ExecutionException, InterruptedException { deleteAlarmRelation(tenantId, entityId, alarmId, oldStatus); createAlarmRelation(tenantId, entityId, alarmId, newStatus, false); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java index 958dcf05b3..0566cb895a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.dao.Dao; import java.util.List; @@ -116,23 +117,12 @@ public interface AssetDao extends Dao { ListenableFuture> findTenantAssetTypesAsync(UUID tenantId); /** - * Find assets by tenantId, customerId and page link. + * Find assets by tenantId, edgeId and page link. * * @param tenantId the tenantId * @param edgeId the edgeId * @param pageLink the page link * @return the list of asset objects */ - List findAssetsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink); - - /** - * Find assets by tenantId, customerId, type and page link. - * - * @param tenantId the tenantId - * @param edgeId the edgeId - * @param type the type - * @param pageLink the page link - * @return the list of asset objects - */ - List findAssetsByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink); + ListenableFuture> findAssetsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java index 907b0399fa..8c0f4cf644 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java @@ -16,6 +16,7 @@ package org.thingsboard.server.dao.asset; +import com.google.common.base.Function; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; @@ -29,12 +30,14 @@ import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.AssetSearchQuery; +import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EdgeId; @@ -42,9 +45,13 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.page.TimePageData; +import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.dao.customer.CustomerDao; +import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.exception.DataValidationException; @@ -52,6 +59,7 @@ import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.tenant.TenantDao; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -89,6 +97,9 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ @Autowired private EntityViewService entityViewService; + @Autowired + private EdgeService edgeService; + @Autowired private CacheManager cacheManager; @@ -285,36 +296,52 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ @Override public Asset assignAssetToEdge(TenantId tenantId, AssetId assetId, EdgeId edgeId) { Asset asset = findAssetById(tenantId, assetId); - asset.setEdgeId(edgeId); - return saveAsset(asset); + Edge edge = edgeService.findEdgeById(tenantId, edgeId); + if (edge == null) { + throw new DataValidationException("Can't assign asset to non-existent edge!"); + } + if (!edge.getTenantId().getId().equals(asset.getTenantId().getId())) { + throw new DataValidationException("Can't assign asset to edge from different tenant!"); + } + try { + createRelation(tenantId, new EntityRelation(edgeId, assetId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE)); + } catch (ExecutionException | InterruptedException e) { + log.warn("[{}] Failed to create asset relation. Edge Id: [{}]", assetId, edgeId); + throw new RuntimeException(e); + } + return asset; } @Override - public Asset unassignAssetFromEdge(TenantId tenantId, AssetId assetId) { + public Asset unassignAssetFromEdge(TenantId tenantId, AssetId assetId, EdgeId edgeId) { Asset asset = findAssetById(tenantId, assetId); - asset.setEdgeId(null); - return saveAsset(asset); + Edge edge = edgeService.findEdgeById(tenantId, edgeId); + if (edge == null) { + throw new DataValidationException("Can't unassign asset from non-existent edge!"); + } + try { + deleteRelation(tenantId, new EntityRelation(edgeId, assetId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE)); + } catch (ExecutionException | InterruptedException e) { + log.warn("[{}] Failed to delete asset relation. Edge Id: [{}]", assetId, edgeId); + throw new RuntimeException(e); + } + return asset; } @Override - public TextPageData findAssetsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TextPageLink pageLink) { + public ListenableFuture> findAssetsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink) { log.trace("Executing findAssetsByTenantIdAndEdgeId, tenantId [{}], edgeId [{}], pageLink [{}]", tenantId, edgeId, pageLink); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(edgeId, INCORRECT_EDGE_ID + edgeId); validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); - List assets = assetDao.findAssetsByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink); - return new TextPageData<>(assets, pageLink); - } - - @Override - public TextPageData findAssetsByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink) { - log.trace("Executing findAssetsByTenantIdAndEdgeIdAndType, tenantId [{}], edgeId [{}], type [{}], pageLink [{}]", tenantId, edgeId, type, pageLink); - validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - validateId(edgeId, INCORRECT_EDGE_ID + edgeId); - validateString(type, "Incorrect type " + type); - validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); - List assets = assetDao.findAssetsByTenantIdAndEdgeIdAndType(tenantId.getId(), edgeId.getId(), type, pageLink); - return new TextPageData<>(assets, pageLink); + ListenableFuture> assets = assetDao.findAssetsByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink); + return Futures.transform(assets, new Function, TimePageData>() { + @Nullable + @Override + public TimePageData apply(@Nullable List assets) { + return new TimePageData<>(assets, pageLink); + } + }, MoreExecutors.directExecutor()); } private DataValidator assetValidator = diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/CassandraAssetDao.java b/dao/src/main/java/org/thingsboard/server/dao/asset/CassandraAssetDao.java index 5f8632516f..87ccef86f1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/CassandraAssetDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/CassandraAssetDao.java @@ -25,16 +25,23 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.page.TimePageLink; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.EntitySubtypeEntity; import org.thingsboard.server.dao.model.nosql.AssetEntity; import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao; +import org.thingsboard.server.dao.relation.RelationDao; import org.thingsboard.server.dao.util.NoSqlDao; import javax.annotation.Nullable; @@ -68,6 +75,9 @@ import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY; @NoSqlDao public class CassandraAssetDao extends CassandraAbstractSearchTextDao implements AssetDao { + @Autowired + private RelationDao relationDao; + @Override protected Class getColumnFamilyClass() { return AssetEntity.class; @@ -190,30 +200,16 @@ public class CassandraAssetDao extends CassandraAbstractSearchTextDao findAssetsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink) { -// log.debug("Try to find assets by tenantId [{}], customerId[{}] and pageLink [{}]", tenantId, customerId, pageLink); -// List assetEntities = findPageWithTextSearch(new TenantId(tenantId), ASSET_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, -// Arrays.asList(eq(ASSET_CUSTOMER_ID_PROPERTY, customerId), -// eq(ASSET_TENANT_ID_PROPERTY, tenantId)), -// pageLink); -// -// log.trace("Found assets [{}] by tenantId [{}], customerId [{}] and pageLink [{}]", assetEntities, tenantId, customerId, pageLink); -// return DaoUtil.convertDataList(assetEntities); - throw new UnsupportedOperationException("Cassandra is not supported yet"); - } - - @Override - public List findAssetsByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink) { -// log.debug("Try to find assets by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", tenantId, customerId, type, pageLink); -// List assetEntities = findPageWithTextSearch(new TenantId(tenantId), ASSET_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, -// Arrays.asList(eq(ASSET_TYPE_PROPERTY, type), -// eq(ASSET_CUSTOMER_ID_PROPERTY, customerId), -// eq(ASSET_TENANT_ID_PROPERTY, tenantId)), -// pageLink); -// -// log.trace("Found assets [{}] by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", assetEntities, tenantId, customerId, type, pageLink); -// return DaoUtil.convertDataList(assetEntities); - throw new UnsupportedOperationException("Cassandra is not supported yet"); + public ListenableFuture> findAssetsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink) { + log.debug("Try to find assets by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink); + ListenableFuture> relations = relationDao.findRelations(new TenantId(tenantId), new EdgeId(edgeId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE, EntityType.ASSET, pageLink); + return Futures.transformAsync(relations, input -> { + List> assetFutures = new ArrayList<>(input.size()); + for (EntityRelation relation : input) { + assetFutures.add(findByIdAsync(new TenantId(tenantId), relation.getTo().getId())); + } + return Futures.successfulAsList(assetFutures); + }, MoreExecutors.directExecutor()); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java index 3658dc22e8..ae3f787e5a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java @@ -162,16 +162,6 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb } } - private void deleteRelation(TenantId tenantId, EntityRelation dashboardRelation) throws ExecutionException, InterruptedException { - log.debug("Deleting Dashboard relation: {}", dashboardRelation); - relationService.deleteRelationAsync(tenantId, dashboardRelation).get(); - } - - private void createRelation(TenantId tenantId, EntityRelation dashboardRelation) throws ExecutionException, InterruptedException { - log.debug("Creating Dashboard relation: {}", dashboardRelation); - relationService.saveRelationAsync(tenantId, dashboardRelation).get(); - } - @Override public void deleteDashboard(TenantId tenantId, DashboardId dashboardId) { log.trace("Executing deleteDashboard [{}]", dashboardId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/CassandraDeviceDao.java b/dao/src/main/java/org/thingsboard/server/dao/device/CassandraDeviceDao.java index 513b313aa0..41d0ff8d2c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/CassandraDeviceDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/CassandraDeviceDao.java @@ -25,16 +25,22 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.page.TimePageLink; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.EntitySubtypeEntity; import org.thingsboard.server.dao.model.nosql.DeviceEntity; import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao; +import org.thingsboard.server.dao.relation.RelationDao; import org.thingsboard.server.dao.util.NoSqlDao; import javax.annotation.Nullable; @@ -68,6 +74,9 @@ import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY; @NoSqlDao public class CassandraDeviceDao extends CassandraAbstractSearchTextDao implements DeviceDao { + @Autowired + private RelationDao relationDao; + @Override protected Class getColumnFamilyClass() { return DeviceEntity.class; @@ -190,30 +199,17 @@ public class CassandraDeviceDao extends CassandraAbstractSearchTextDao findDevicesByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink) { -// log.debug("Try to find devices by tenantId [{}], customerId[{}] and pageLink [{}]", tenantId, customerId, pageLink); -// List deviceEntities = findPageWithTextSearch(new TenantId(tenantId), DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, -// Arrays.asList(eq(DEVICE_CUSTOMER_ID_PROPERTY, customerId), -// eq(DEVICE_TENANT_ID_PROPERTY, tenantId)), -// pageLink); -// -// log.trace("Found devices [{}] by tenantId [{}], customerId [{}] and pageLink [{}]", deviceEntities, tenantId, customerId, pageLink); -// return DaoUtil.convertDataList(deviceEntities); - throw new UnsupportedOperationException("Cassandra is not supported yet"); + public ListenableFuture> findDevicesByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink) { + log.debug("Try to find devices by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink); + ListenableFuture> relations = relationDao.findRelations(new TenantId(tenantId), new EdgeId(edgeId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE, EntityType.DEVICE, pageLink); + return Futures.transformAsync(relations, input -> { + List> deviceFutures = new ArrayList<>(input.size()); + for (EntityRelation relation : input) { + deviceFutures.add(findByIdAsync(new TenantId(tenantId), relation.getTo().getId())); + } + return Futures.successfulAsList(deviceFutures); + }, MoreExecutors.directExecutor()); } - @Override - public List findDevicesByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink) { -// log.debug("Try to find devices by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", tenantId, customerId, type, pageLink); -// List deviceEntities = findPageWithTextSearch(new TenantId(tenantId), DEVICE_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, -// Arrays.asList(eq(DEVICE_TYPE_PROPERTY, type), -// eq(DEVICE_CUSTOMER_ID_PROPERTY, customerId), -// eq(DEVICE_TENANT_ID_PROPERTY, tenantId)), -// pageLink); -// -// log.trace("Found devices [{}] by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", deviceEntities, tenantId, customerId, type, pageLink); -// return DaoUtil.convertDataList(deviceEntities); - throw new UnsupportedOperationException("Cassandra is not supported yet"); - } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java index 856243a4a5..d6687b7278 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.dao.Dao; import java.util.List; @@ -124,16 +125,5 @@ public interface DeviceDao extends Dao { * @param pageLink the page link * @return the list of device objects */ - List findDevicesByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink); - - /** - * Find devices by tenantId, edgeId, type and page link. - * - * @param tenantId the tenantId - * @param edgeId the edgeId - * @param type the type - * @param pageLink the page link - * @return the list of device objects - */ - List findDevicesByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink); + ListenableFuture> findDevicesByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index cb151bcd97..c8f24262a1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -41,19 +41,26 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.page.TimePageData; +import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentialsType; import org.thingsboard.server.dao.customer.CustomerDao; +import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; +import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.dao.tenant.TenantDao; import javax.annotation.Nullable; @@ -98,6 +105,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @Autowired private EntityViewService entityViewService; + @Autowired + private EdgeService edgeService; + @Autowired private CacheManager cacheManager; @@ -324,36 +334,52 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @Override public Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId) { Device device = findDeviceById(tenantId, deviceId); - device.setEdgeId(edgeId); - return saveDevice(device); + Edge edge = edgeService.findEdgeById(tenantId, edgeId); + if (edge == null) { + throw new DataValidationException("Can't assign device to non-existent edge!"); + } + if (!edge.getTenantId().getId().equals(device.getTenantId().getId())) { + throw new DataValidationException("Can't assign device to edge from different tenant!"); + } + try { + createRelation(tenantId, new EntityRelation(edgeId, deviceId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE)); + } catch (ExecutionException | InterruptedException e) { + log.warn("[{}] Failed to create device relation. Edge Id: [{}]", deviceId, edgeId); + throw new RuntimeException(e); + } + return device; } @Override - public Device unassignDeviceFromEdge(TenantId tenantId, DeviceId deviceId) { + public Device unassignDeviceFromEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId) { Device device = findDeviceById(tenantId, deviceId); - device.setEdgeId(null); - return saveDevice(device); + Edge edge = edgeService.findEdgeById(tenantId, edgeId); + if (edge == null) { + throw new DataValidationException("Can't unassign device from non-existent edge!"); + } + try { + deleteRelation(tenantId, new EntityRelation(edgeId, deviceId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE)); + } catch (ExecutionException | InterruptedException e) { + log.warn("[{}] Failed to delete device relation. Edge Id: [{}]", deviceId, edgeId); + throw new RuntimeException(e); + } + return device; } @Override - public TextPageData findDevicesByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TextPageLink pageLink) { + public ListenableFuture> findDevicesByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink) { log.trace("Executing findDevicesByTenantIdAndEdgeId, tenantId [{}], edgeId [{}], pageLink [{}]", tenantId, edgeId, pageLink); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(edgeId, INCORRECT_EDGE_ID + edgeId); validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); - List devices = deviceDao.findDevicesByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink); - return new TextPageData<>(devices, pageLink); - } - - @Override - public TextPageData findDevicesByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink) { - log.trace("Executing findDevicesByTenantIdAndEdgeIdAndType, tenantId [{}], edgeId [{}], type [{}], pageLink [{}]", tenantId, edgeId, type, pageLink); - validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - validateId(edgeId, INCORRECT_EDGE_ID + edgeId); - validateString(type, "Incorrect type " + type); - validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); - List devices = deviceDao.findDevicesByTenantIdAndEdgeIdAndType(tenantId.getId(), edgeId.getId(), type, pageLink); - return new TextPageData<>(devices, pageLink); + ListenableFuture> devices = deviceDao.findDevicesByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink); + return Futures.transform(devices, new Function, TimePageData>() { + @Nullable + @Override + public TimePageData apply(@Nullable List devices) { + return new TimePageData<>(devices, pageLink); + } + }, MoreExecutors.directExecutor()); } private DataValidator deviceValidator = diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java index f974cabc62..25c83ed031 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java @@ -62,6 +62,7 @@ import org.thingsboard.server.common.data.page.TimePageData; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainType; @@ -75,6 +76,7 @@ import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.event.EventService; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; @@ -144,6 +146,9 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic @Autowired private EntityViewService entityViewService; + @Autowired + private RelationService relationService; + private ExecutorService tsCallBackExecutor; @PostConstruct @@ -219,7 +224,7 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic dashboardService.unassignEdgeDashboards(tenantId, edgeId); // TODO: validate that rule chains are removed by deleteEntityRelations(tenantId, edgeId); call - ruleChainService.unassignEdgeRuleChains(tenantId, edgeId); + ruleChainService.unassignEdgeRuleChains(tenantId, edgeId); List list = new ArrayList<>(); list.add(edge.getTenantId()); @@ -385,15 +390,18 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic } private void processCustomTbMsg(TenantId tenantId, TbMsg tbMsg, FutureCallback callback) { - EdgeId edgeId = getEdgeIdByOriginatorId(tenantId, tbMsg.getOriginator()); - EdgeQueueEntityType edgeQueueEntityType = getEdgeQueueTypeByEntityType(tbMsg.getOriginator().getEntityType()); - if (edgeId != null && edgeQueueEntityType != null) { - try { - saveEventToEdgeQueue(tenantId, edgeId, edgeQueueEntityType, tbMsg.getType(), Base64.encodeBase64String(TbMsg.toByteArray(tbMsg)), callback); - } catch (IOException e) { - log.error("Error while saving custom tbMsg into Edge Queue", e); + ListenableFuture edgeIdFuture = getEdgeIdByOriginatorId(tenantId, tbMsg.getOriginator()); + Futures.transform(edgeIdFuture, edgeId -> { + EdgeQueueEntityType edgeQueueEntityType = getEdgeQueueTypeByEntityType(tbMsg.getOriginator().getEntityType()); + if (edgeId != null && edgeQueueEntityType != null) { + try { + saveEventToEdgeQueue(tenantId, edgeId, edgeQueueEntityType, tbMsg.getType(), Base64.encodeBase64String(TbMsg.toByteArray(tbMsg)), callback); + } catch (IOException e) { + log.error("Error while saving custom tbMsg into Edge Queue", e); + } } - } + return null; + }, MoreExecutors.directExecutor()); } private EdgeQueueEntityType getEdgeQueueTypeByEntityType(EntityType entityType) { @@ -410,23 +418,30 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic } } - private EdgeId getEdgeIdByOriginatorId(TenantId tenantId, EntityId originatorId) { - switch (originatorId.getEntityType()) { - case DEVICE: - Device device = deviceService.findDeviceById(tenantId, new DeviceId(originatorId.getId())); - return device.getEdgeId(); - case ASSET: - Asset asset = assetService.findAssetById(tenantId, new AssetId(originatorId.getId())); - return asset.getEdgeId(); - case ENTITY_VIEW: - EntityView entityView = entityViewService.findEntityViewById(tenantId, new EntityViewId(originatorId.getId())); - return entityView.getEdgeId(); - default: - log.info("Unsupported entity type: [{}]", originatorId.getEntityType()); - return null; + private ListenableFuture getEdgeIdByOriginatorId(TenantId tenantId, EntityId originatorId) { + List originatorEdgeRelations = relationService.findByToAndType(tenantId, originatorId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE); + if (originatorEdgeRelations != null && originatorEdgeRelations.size() > 0) { + return Futures.immediateFuture(new EdgeId(originatorEdgeRelations.get(0).getFrom().getId())); + } else { + return Futures.immediateFuture(null); } } + private void pushEventToEdge(TenantId tenantId, EntityId originatorId, EdgeQueueEntityType edgeQueueEntityType, TbMsg tbMsg, FutureCallback callback) { + ListenableFuture edgeIdFuture = getEdgeIdByOriginatorId(tenantId, originatorId); + Futures.transform(edgeIdFuture, edgeId -> { + if (edgeId != null) { + try { + pushEventToEdge(tenantId, edgeId, edgeQueueEntityType, tbMsg, callback); + } catch (Exception e) { + log.error("Failed to push event to edge, edgeId [{}], tbMsg [{}]", edgeId, tbMsg, e); + } + } + return null; + }, + MoreExecutors.directExecutor()); + } + private void processDevice(TenantId tenantId, TbMsg tbMsg, FutureCallback callback) throws IOException { switch (tbMsg.getType()) { case DataConstants.ENTITY_ASSIGNED_TO_EDGE: @@ -437,9 +452,7 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic case DataConstants.ENTITY_CREATED: case DataConstants.ENTITY_UPDATED: Device device = mapper.readValue(tbMsg.getData(), Device.class); - if (device.getEdgeId() != null) { - pushEventToEdge(tenantId, device.getEdgeId(), EdgeQueueEntityType.DEVICE, tbMsg, callback); - } + pushEventToEdge(tenantId, device.getId(), EdgeQueueEntityType.DEVICE, tbMsg, callback); break; default: log.warn("Unsupported msgType [{}], tbMsg [{}]", tbMsg.getType(), tbMsg); @@ -471,9 +484,7 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic case DataConstants.ENTITY_CREATED: case DataConstants.ENTITY_UPDATED: Asset asset = mapper.readValue(tbMsg.getData(), Asset.class); - if (asset.getEdgeId() != null) { - pushEventToEdge(tenantId, asset.getEdgeId(), EdgeQueueEntityType.ASSET, tbMsg, callback); - } + pushEventToEdge(tenantId, asset.getId(), EdgeQueueEntityType.ASSET, tbMsg, callback); break; default: log.warn("Unsupported msgType [{}], tbMsg [{}]", tbMsg.getType(), tbMsg); @@ -490,9 +501,7 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic case DataConstants.ENTITY_CREATED: case DataConstants.ENTITY_UPDATED: EntityView entityView = mapper.readValue(tbMsg.getData(), EntityView.class); - if (entityView.getEdgeId() != null) { - pushEventToEdge(tenantId, entityView.getEdgeId(), EdgeQueueEntityType.ENTITY_VIEW, tbMsg, callback); - } + pushEventToEdge(tenantId, entityView.getId(), EdgeQueueEntityType.ENTITY_VIEW, tbMsg, callback); break; default: log.warn("Unsupported msgType [{}], tbMsg [{}]", tbMsg.getType(), tbMsg); @@ -507,10 +516,9 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic case DataConstants.ALARM_ACK: case DataConstants.ALARM_CLEAR: Alarm alarm = mapper.readValue(tbMsg.getData(), Alarm.class); - EdgeId edgeId = getEdgeIdByOriginatorId(tenantId, alarm.getOriginator()); EdgeQueueEntityType edgeQueueEntityType = getEdgeQueueTypeByEntityType(alarm.getOriginator().getEntityType()); - if (edgeId != null && edgeQueueEntityType != null) { - pushEventToEdge(tenantId, edgeId, EdgeQueueEntityType.ALARM, tbMsg, callback); + if (edgeQueueEntityType != null) { + pushEventToEdge(tenantId, alarm.getOriginator(), EdgeQueueEntityType.ALARM, tbMsg, callback); } break; default: diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java index 5c7f6c88e2..17fa7bcb3e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java @@ -21,10 +21,12 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.dao.relation.RelationService; import javax.annotation.PostConstruct; import java.util.Optional; +import java.util.concurrent.ExecutionException; @Slf4j public abstract class AbstractEntityService { @@ -42,6 +44,16 @@ public abstract class AbstractEntityService { sqlDatabaseUsed = "sql".equalsIgnoreCase(databaseType); } + protected void createRelation(TenantId tenantId, EntityRelation relation) throws ExecutionException, InterruptedException { + log.debug("Creating relation: {}", relation); + relationService.saveRelation(tenantId, relation); + } + + protected void deleteRelation(TenantId tenantId, EntityRelation relation) throws ExecutionException, InterruptedException { + log.debug("Deleting relation: {}", relation); + relationService.deleteRelation(tenantId, relation); + } + protected void deleteEntityRelations(TenantId tenantId, EntityId entityId) { log.trace("Executing deleteEntityRelations [{}]", entityId); relationService.deleteEntityRelations(tenantId, entityId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java index ae08cddb05..c65e7d70f2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java @@ -25,16 +25,23 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.page.TimePageLink; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.EntitySubtypeEntity; import org.thingsboard.server.dao.model.nosql.EntityViewEntity; import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao; +import org.thingsboard.server.dao.relation.RelationDao; import org.thingsboard.server.dao.util.NoSqlDao; import javax.annotation.Nullable; @@ -73,6 +80,9 @@ import static org.thingsboard.server.dao.model.ModelConstants.TENANT_ID_PROPERTY @NoSqlDao public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao implements EntityViewDao { + @Autowired + private RelationDao relationDao; + @Override protected Class getColumnFamilyClass() { return EntityViewEntity.class; @@ -186,30 +196,16 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao findEntityViewsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink) { -// log.debug("Try to find entity views by tenantId [{}], customerId[{}] and pageLink [{}]", -// tenantId, customerId, pageLink); -// List entityViewEntities = findPageWithTextSearch(new TenantId(tenantId), -// ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_CF, -// Arrays.asList(eq(CUSTOMER_ID_PROPERTY, customerId), eq(TENANT_ID_PROPERTY, tenantId)), -// pageLink); -// log.trace("Found find entity views [{}] by tenantId [{}], customerId [{}] and pageLink [{}]", -// entityViewEntities, tenantId, customerId, pageLink); -// return DaoUtil.convertDataList(entityViewEntities); - throw new UnsupportedOperationException("Cassandra is not supported yet"); + public ListenableFuture> findEntityViewsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink) { + log.debug("Try to find entity views by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink); + ListenableFuture> relations = relationDao.findRelations(new TenantId(tenantId), new EdgeId(edgeId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE, EntityType.ENTITY_VIEW, pageLink); + return Futures.transformAsync(relations, input -> { + List> entityViewFutures = new ArrayList<>(input.size()); + for (EntityRelation relation : input) { + entityViewFutures.add(findByIdAsync(new TenantId(tenantId), relation.getTo().getId())); + } + return Futures.successfulAsList(entityViewFutures); + }, MoreExecutors.directExecutor()); } - @Override - public List findEntityViewsByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink) { -// log.debug("Try to find entity views by tenantId [{}], customerId[{}], type [{}] and pageLink [{}]", -// tenantId, customerId, type, pageLink); -// List entityViewEntities = findPageWithTextSearch(new TenantId(tenantId), -// ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_TYPE_CF, -// Arrays.asList(eq(DEVICE_TYPE_PROPERTY, type), eq(CUSTOMER_ID_PROPERTY, customerId), eq(TENANT_ID_PROPERTY, tenantId)), -// pageLink); -// log.trace("Found find entity views [{}] by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", -// entityViewEntities, tenantId, customerId, type, pageLink); -// return DaoUtil.convertDataList(entityViewEntities); - throw new UnsupportedOperationException("Cassandra is not supported yet"); - } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java index cefa28a916..cd9501a70b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.dao.Dao; import java.util.List; @@ -110,22 +111,8 @@ public interface EntityViewDao extends Dao { * @param pageLink the page link * @return the list of entity view objects */ - List findEntityViewsByTenantIdAndEdgeId(UUID tenantId, - UUID edgeId, - TextPageLink pageLink); - - /** - * Find entity views by tenantId, edgeId, type and page link. - * - * @param tenantId the tenantId - * @param edgeId the edgeId - * @param type the type - * @param pageLink the page link - * @return the list of entity view objects - */ - List findEntityViewsByTenantIdAndEdgeIdAndType(UUID tenantId, - UUID edgeId, - String type, - TextPageLink pageLink); + ListenableFuture> findEntityViewsByTenantIdAndEdgeId(UUID tenantId, + UUID edgeId, + TimePageLink pageLink); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index 70be8c4486..907072e549 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -30,10 +30,12 @@ import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Caching; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EdgeId; @@ -42,9 +44,13 @@ import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.page.TimePageData; +import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.dao.customer.CustomerDao; +import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; @@ -58,6 +64,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Optional; +import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import static org.thingsboard.server.common.data.CacheConstants.ENTITY_VIEW_CACHE; @@ -88,6 +95,9 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Autowired private CustomerDao customerDao; + @Autowired + private EdgeService edgeService; + @Autowired private CacheManager cacheManager; @@ -285,47 +295,56 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti }, MoreExecutors.directExecutor()); } - - @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}") @Override public EntityView assignEntityViewToEdge(TenantId tenantId, EntityViewId entityViewId, EdgeId edgeId) { EntityView entityView = findEntityViewById(tenantId, entityViewId); - entityView.setEdgeId(edgeId); - return saveEntityView(entityView); + Edge edge = edgeService.findEdgeById(tenantId, edgeId); + if (edge == null) { + throw new DataValidationException("Can't assign entityView to non-existent edge!"); + } + if (!edge.getTenantId().getId().equals(entityView.getTenantId().getId())) { + throw new DataValidationException("Can't assign entityView to edge from different tenant!"); + } + try { + createRelation(tenantId, new EntityRelation(edgeId, entityViewId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE)); + } catch (ExecutionException | InterruptedException e) { + log.warn("[{}] Failed to create entityView relation. Edge Id: [{}]", entityViewId, edgeId); + throw new RuntimeException(e); + } + return entityView; } - @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}") @Override - public EntityView unassignEntityViewFromEdge(TenantId tenantId, EntityViewId entityViewId) { + public EntityView unassignEntityViewFromEdge(TenantId tenantId, EntityViewId entityViewId, EdgeId edgeId) { EntityView entityView = findEntityViewById(tenantId, entityViewId); - entityView.setEdgeId(null); - return saveEntityView(entityView); - } - - @Override - public TextPageData findEntityViewsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, - TextPageLink pageLink) { - log.trace("Executing findEntityViewsByTenantIdAndEdgeId, tenantId [{}], edgeId [{}]," + - " pageLink [{}]", tenantId, edgeId, pageLink); - validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - validateId(edgeId, INCORRECT_EDGE_ID + edgeId); - validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); - List entityViews = entityViewDao.findEntityViewsByTenantIdAndEdgeId(tenantId.getId(), - edgeId.getId(), pageLink); - return new TextPageData<>(entityViews, pageLink); + Edge edge = edgeService.findEdgeById(tenantId, edgeId); + if (edge == null) { + throw new DataValidationException("Can't unassign entityView from non-existent edge!"); + } + try { + deleteRelation(tenantId, new EntityRelation(edgeId, entityViewId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE)); + } catch (ExecutionException | InterruptedException e) { + log.warn("[{}] Failed to delete entityView relation. Edge Id: [{}]", entityViewId, edgeId); + throw new RuntimeException(e); + } + return entityView; } @Override - public TextPageData findEntityViewsByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink) { - log.trace("Executing findEntityViewsByTenantIdAndEdgeIdAndType, tenantId [{}], edgeId [{}]," + - " pageLink [{}], type [{}]", tenantId, edgeId, pageLink, type); + public ListenableFuture> findEntityViewsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, + TimePageLink pageLink) { + log.trace("Executing findEntityViewsByTenantIdAndEdgeId, tenantId [{}], edgeId [{}], pageLink [{}]", tenantId, edgeId, pageLink); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(edgeId, INCORRECT_EDGE_ID + edgeId); validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); - validateString(type, "Incorrect type " + type); - List entityViews = entityViewDao.findEntityViewsByTenantIdAndEdgeIdAndType(tenantId.getId(), - edgeId.getId(), type, pageLink); - return new TextPageData<>(entityViews, pageLink); + ListenableFuture> entityViews = entityViewDao.findEntityViewsByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink); + return Futures.transform(entityViews, new Function, TimePageData>() { + @Nullable + @Override + public TimePageData apply(@Nullable List entityViews) { + return new TimePageData<>(entityViews, pageLink); + } + }, MoreExecutors.directExecutor()); } private DataValidator entityViewValidator = diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index 7c089f8975..dcdf9460bf 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -142,7 +142,6 @@ public class ModelConstants { public static final String DEVICE_TYPE_PROPERTY = "type"; public static final String DEVICE_LABEL_PROPERTY = "label"; public static final String DEVICE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY; - public static final String DEVICE_EDGE_ID_PROPERTY = "edge_id"; public static final String DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_and_search_text"; public static final String DEVICE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_by_type_and_search_text"; 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 { public static final String ENTITY_VIEW_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; public static final String ENTITY_VIEW_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY; public static final String ENTITY_VIEW_NAME_PROPERTY = DEVICE_NAME_PROPERTY; - public static final String ENTITY_VIEW_EDGE_ID_PROPERTY = "edge_id"; public static final String ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_CF = "entity_view_by_tenant_and_customer"; public static final String ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_TYPE_CF = "entity_view_by_tenant_and_customer_and_type"; 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 { public static final String ASSET_TYPE_PROPERTY = "type"; public static final String ASSET_LABEL_PROPERTY = "label"; public static final String ASSET_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY; - public static final String ASSET_EDGE_ID_PROPERTY = "edge_id"; public static final String ASSET_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_tenant_and_search_text"; public static final String ASSET_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_tenant_by_type_and_search_text"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/AssetEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/AssetEntity.java index 56849bca5e..aaa60f0b64 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/AssetEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/AssetEntity.java @@ -25,7 +25,6 @@ import lombok.ToString; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; -import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.SearchTextEntity; import org.thingsboard.server.dao.model.type.JsonCodec; @@ -35,11 +34,10 @@ import java.util.UUID; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_ADDITIONAL_INFO_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_COLUMN_FAMILY_NAME; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_CUSTOMER_ID_PROPERTY; -import static org.thingsboard.server.dao.model.ModelConstants.ASSET_EDGE_ID_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.ASSET_LABEL_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_NAME_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_TENANT_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_TYPE_PROPERTY; -import static org.thingsboard.server.dao.model.ModelConstants.ASSET_LABEL_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY; @@ -64,10 +62,6 @@ public final class AssetEntity implements SearchTextEntity { @Column(name = ASSET_TYPE_PROPERTY) private String type; - @PartitionKey(value = 4) - @Column(name = ASSET_EDGE_ID_PROPERTY) - private UUID edgeId; - @Column(name = ASSET_NAME_PROPERTY) private String name; @@ -94,9 +88,6 @@ public final class AssetEntity implements SearchTextEntity { if (asset.getCustomerId() != null) { this.customerId = asset.getCustomerId().getId(); } - if (asset.getEdgeId() != null) { - this.edgeId = asset.getEdgeId().getId(); - } this.name = asset.getName(); this.type = asset.getType(); this.label = asset.getLabel(); @@ -127,14 +118,6 @@ public final class AssetEntity implements SearchTextEntity { this.customerId = customerId; } - public UUID getEdgeId() { - return edgeId; - } - - public void setEdgeId(UUID edgeId) { - this.edgeId = edgeId; - } - public String getName() { return name; } @@ -183,9 +166,6 @@ public final class AssetEntity implements SearchTextEntity { if (customerId != null) { asset.setCustomerId(new CustomerId(customerId)); } - if (edgeId != null) { - asset.setEdgeId(new EdgeId(edgeId)); - } asset.setName(name); asset.setType(type); asset.setLabel(label); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/DeviceEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/DeviceEntity.java index 284ba4f164..f99b03c220 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/DeviceEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/DeviceEntity.java @@ -25,14 +25,21 @@ import lombok.ToString; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; -import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.SearchTextEntity; import org.thingsboard.server.dao.model.type.JsonCodec; import java.util.UUID; -import static org.thingsboard.server.dao.model.ModelConstants.*; +import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_ADDITIONAL_INFO_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_COLUMN_FAMILY_NAME; +import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_CUSTOMER_ID_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_LABEL_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_NAME_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_TENANT_ID_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_TYPE_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY; @Table(name = DEVICE_COLUMN_FAMILY_NAME) @EqualsAndHashCode @@ -55,10 +62,6 @@ public final class DeviceEntity implements SearchTextEntity { @Column(name = DEVICE_TYPE_PROPERTY) private String type; - @PartitionKey(value = 4) - @Column(name = DEVICE_EDGE_ID_PROPERTY) - private UUID edgeId; - @Column(name = DEVICE_NAME_PROPERTY) private String name; @@ -85,9 +88,6 @@ public final class DeviceEntity implements SearchTextEntity { if (device.getCustomerId() != null) { this.customerId = device.getCustomerId().getId(); } - if (device.getEdgeId() != null) { - this.edgeId = device.getEdgeId().getId(); - } this.name = device.getName(); this.type = device.getType(); this.label = device.getLabel(); @@ -118,14 +118,6 @@ public final class DeviceEntity implements SearchTextEntity { this.customerId = customerId; } - public UUID getEdgeId() { - return edgeId; - } - - public void setEdgeId(UUID edgeId) { - this.edgeId = edgeId; - } - public String getName() { return name; } @@ -174,9 +166,6 @@ public final class DeviceEntity implements SearchTextEntity { if (customerId != null) { device.setCustomerId(new CustomerId(customerId)); } - if (edgeId != null) { - device.setEdgeId(new EdgeId(edgeId)); - } device.setName(name); device.setType(type); device.setLabel(label); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EntityViewEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EntityViewEntity.java index 3aca4ff739..cc5fb9d844 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EntityViewEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EntityViewEntity.java @@ -29,7 +29,6 @@ import org.hibernate.annotations.Type; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.id.CustomerId; -import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; @@ -42,7 +41,6 @@ import javax.persistence.Enumerated; import java.io.IOException; import java.util.UUID; -import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_EDGE_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_TYPE_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_TYPE_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_TABLE_FAMILY_NAME; @@ -71,10 +69,6 @@ public class EntityViewEntity implements SearchTextEntity { @Column(name = DEVICE_TYPE_PROPERTY) private String type; - @PartitionKey(value = 4) - @Column(name = DEVICE_EDGE_ID_PROPERTY) - private UUID edgeId; - @Enumerated(EnumType.STRING) @Column(name = ENTITY_TYPE_PROPERTY) private EntityType entityType; @@ -121,9 +115,6 @@ public class EntityViewEntity implements SearchTextEntity { if (entityView.getCustomerId() != null) { this.customerId = entityView.getCustomerId().getId(); } - if (entityView.getEdgeId() != null) { - this.edgeId = entityView.getEdgeId().getId(); - } this.type = entityView.getType(); this.name = entityView.getName(); try { @@ -155,9 +146,6 @@ public class EntityViewEntity implements SearchTextEntity { if (customerId != null) { entityView.setCustomerId(new CustomerId(customerId)); } - if (edgeId != null) { - entityView.setEdgeId(new EdgeId(edgeId)); - } entityView.setType(type); entityView.setName(name); try { diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AssetEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AssetEntity.java index f11b13e87b..746c6df33f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AssetEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AssetEntity.java @@ -25,7 +25,6 @@ import org.thingsboard.server.common.data.UUIDConverter; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; -import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.BaseSqlEntity; import org.thingsboard.server.dao.model.ModelConstants; @@ -38,11 +37,10 @@ import javax.persistence.Table; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_COLUMN_FAMILY_NAME; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_CUSTOMER_ID_PROPERTY; -import static org.thingsboard.server.dao.model.ModelConstants.ASSET_EDGE_ID_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.ASSET_LABEL_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_NAME_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_TENANT_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_TYPE_PROPERTY; -import static org.thingsboard.server.dao.model.ModelConstants.ASSET_LABEL_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY; @Data @@ -58,9 +56,6 @@ public final class AssetEntity extends BaseSqlEntity implements SearchTex @Column(name = ASSET_CUSTOMER_ID_PROPERTY) private String customerId; - @Column(name = ASSET_EDGE_ID_PROPERTY) - private String edgeId; - @Column(name = ASSET_NAME_PROPERTY) private String name; @@ -91,9 +86,6 @@ public final class AssetEntity extends BaseSqlEntity implements SearchTex if (asset.getCustomerId() != null) { this.customerId = UUIDConverter.fromTimeUUID(asset.getCustomerId().getId()); } - if (asset.getEdgeId() != null) { - this.edgeId = UUIDConverter.fromTimeUUID(asset.getEdgeId().getId()); - } this.name = asset.getName(); this.type = asset.getType(); this.label = asset.getLabel(); @@ -124,9 +116,6 @@ public final class AssetEntity extends BaseSqlEntity implements SearchTex if (customerId != null) { asset.setCustomerId(new CustomerId(UUIDConverter.fromString(customerId))); } - if (edgeId != null) { - asset.setEdgeId(new EdgeId(UUIDConverter.fromString(edgeId))); - } asset.setName(name); asset.setType(type); asset.setLabel(label); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceEntity.java index 06c496a1f4..0d10adcf2b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceEntity.java @@ -24,7 +24,6 @@ import org.hibernate.annotations.TypeDef; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; -import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.BaseSqlEntity; import org.thingsboard.server.dao.model.ModelConstants; @@ -48,9 +47,6 @@ public final class DeviceEntity extends BaseSqlEntity implements SearchT @Column(name = ModelConstants.DEVICE_CUSTOMER_ID_PROPERTY) private String customerId; - @Column(name = ModelConstants.DEVICE_EDGE_ID_PROPERTY) - private String edgeId; - @Column(name = ModelConstants.DEVICE_TYPE_PROPERTY) private String type; @@ -81,9 +77,6 @@ public final class DeviceEntity extends BaseSqlEntity implements SearchT if (device.getCustomerId() != null) { this.customerId = toString(device.getCustomerId().getId()); } - if (device.getEdgeId() != null) { - this.edgeId = toString(device.getEdgeId().getId()); - } this.name = device.getName(); this.type = device.getType(); this.label = device.getLabel(); @@ -110,9 +103,6 @@ public final class DeviceEntity extends BaseSqlEntity implements SearchT if (customerId != null) { device.setCustomerId(new CustomerId(toUUID(customerId))); } - if (edgeId != null) { - device.setEdgeId(new EdgeId(toUUID(edgeId))); - } device.setName(name); device.setType(type); device.setLabel(label); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityViewEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityViewEntity.java index 9ea75eb0c2..62a786f459 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityViewEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityViewEntity.java @@ -26,7 +26,6 @@ import org.hibernate.annotations.TypeDef; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.id.CustomerId; -import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; @@ -66,9 +65,6 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc @Column(name = ModelConstants.ENTITY_VIEW_CUSTOMER_ID_PROPERTY) private String customerId; - @Column(name = ModelConstants.ENTITY_VIEW_EDGE_ID_PROPERTY) - private String edgeId; - @Column(name = ModelConstants.DEVICE_TYPE_PROPERTY) private String type; @@ -111,9 +107,6 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc if (entityView.getCustomerId() != null) { this.customerId = toString(entityView.getCustomerId().getId()); } - if (entityView.getEdgeId() != null) { - this.edgeId = toString(entityView.getEdgeId().getId()); - } this.type = entityView.getType(); this.name = entityView.getName(); try { @@ -151,9 +144,6 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc if (customerId != null) { entityView.setCustomerId(new CustomerId(toUUID(customerId))); } - if (edgeId != null) { - entityView.setEdgeId(new EdgeId(toUUID(edgeId))); - } entityView.setType(type); entityView.setName(name); try { diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index a667092231..d0c37903a8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -467,8 +467,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC return Futures.transform(ruleChains, new Function, TimePageData>() { @Nullable @Override - public TimePageData apply(@Nullable List ruleChain) { - return new TimePageData<>(ruleChain, pageLink); + public TimePageData apply(@Nullable List ruleChains) { + return new TimePageData<>(ruleChains, pageLink); } }, MoreExecutors.directExecutor()); } @@ -557,15 +557,6 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC ruleNodeDao.removeById(tenantId, entityId.getId()); } - private void createRelation(TenantId tenantId, EntityRelation relation) throws ExecutionException, InterruptedException { - log.debug("Creating relation: {}", relation); - relationService.saveRelation(tenantId, relation); - } - - private void deleteRelation(TenantId tenantId, EntityRelation relation) throws ExecutionException, InterruptedException { - log.debug("Deleting relation: {}", relation); - relationService.deleteRelation(tenantId, relation); - } private DataValidator ruleChainValidator = new DataValidator() { diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/CassandraRuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/rule/CassandraRuleChainDao.java index f3916e8cb5..d636281c2a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/CassandraRuleChainDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/CassandraRuleChainDao.java @@ -96,7 +96,7 @@ public class CassandraRuleChainDao extends CassandraAbstractSearchTextDao> findRuleChainsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink) { log.debug("Try to find rule chains by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink); - ListenableFuture> relations = relationDao.findRelations(new TenantId(tenantId), new EdgeId(edgeId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE, EntityType.DASHBOARD, pageLink); + ListenableFuture> relations = relationDao.findRelations(new TenantId(tenantId), new EdgeId(edgeId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE, EntityType.RULE_CHAIN, pageLink); return Futures.transformAsync(relations, input -> { List> ruleChainFutures = new ArrayList<>(input.size()); for (EntityRelation relation : input) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java index 0f00e8c969..7b30d070bb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java @@ -77,26 +77,4 @@ public interface AssetRepository extends CrudRepository { @Query("SELECT DISTINCT a.type FROM AssetEntity a WHERE a.tenantId = :tenantId") List findTenantAssetTypes(@Param("tenantId") String tenantId); - - @Query("SELECT a FROM AssetEntity a WHERE a.tenantId = :tenantId " + - "AND a.edgeId = :edgeId " + - "AND LOWER(a.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " + - "AND a.id > :idOffset ORDER BY a.id") - List findByTenantIdAndEdgeId(@Param("tenantId") String tenantId, - @Param("edgeId") String edgeId, - @Param("textSearch") String textSearch, - @Param("idOffset") String idOffset, - Pageable pageable); - - @Query("SELECT a FROM AssetEntity a WHERE a.tenantId = :tenantId " + - "AND a.edgeId = :edgeId AND a.type = :type " + - "AND LOWER(a.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " + - "AND a.id > :idOffset ORDER BY a.id") - List findByTenantIdAndEdgeIdAndType(@Param("tenantId") String tenantId, - @Param("edgeId") String edgeId, - @Param("type") String type, - @Param("textSearch") String textSearch, - @Param("idOffset") String idOffset, - Pageable pageable); - } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java index 88247e0f76..4d96bb936a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java @@ -15,19 +15,28 @@ */ package org.thingsboard.server.dao.sql.asset; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.PageRequest; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.page.TimePageLink; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.asset.AssetDao; import org.thingsboard.server.dao.model.sql.AssetEntity; +import org.thingsboard.server.dao.relation.RelationDao; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; import org.thingsboard.server.dao.util.SqlDao; @@ -47,11 +56,15 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID_STR; */ @Component @SqlDao +@Slf4j public class JpaAssetDao extends JpaAbstractSearchTextDao implements AssetDao { @Autowired private AssetRepository assetRepository; + @Autowired + private RelationDao relationDao; + @Override protected Class getEntityClass() { return AssetEntity.class; @@ -141,27 +154,16 @@ public class JpaAssetDao extends JpaAbstractSearchTextDao im } @Override - public List findAssetsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink) { - return DaoUtil.convertDataList(assetRepository - .findByTenantIdAndEdgeId( - fromTimeUUID(tenantId), - fromTimeUUID(edgeId), - Objects.toString(pageLink.getTextSearch(), ""), - pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), - PageRequest.of(0, pageLink.getLimit()))); - } - - - @Override - public List findAssetsByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink) { - return DaoUtil.convertDataList(assetRepository - .findByTenantIdAndEdgeIdAndType( - fromTimeUUID(tenantId), - fromTimeUUID(edgeId), - type, - Objects.toString(pageLink.getTextSearch(), ""), - pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), - PageRequest.of(0, pageLink.getLimit()))); + public ListenableFuture> findAssetsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink) { + log.debug("Try to find assets by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink); + ListenableFuture> relations = relationDao.findRelations(new TenantId(tenantId), new EdgeId(edgeId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE, EntityType.ASSET, pageLink); + return Futures.transformAsync(relations, input -> { + List> assetFutures = new ArrayList<>(input.size()); + for (EntityRelation relation : input) { + assetFutures.add(findByIdAsync(new TenantId(tenantId), relation.getTo().getId())); + } + return Futures.successfulAsList(assetFutures); + }, MoreExecutors.directExecutor()); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java index d8544ea4c4..16ff6f1b52 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java @@ -85,26 +85,4 @@ public interface DeviceRepository extends CrudRepository { List findDevicesByTenantIdAndCustomerIdAndIdIn(String tenantId, String customerId, List deviceIds); List findDevicesByTenantIdAndIdIn(String tenantId, List deviceIds); - - @Query("SELECT d FROM DeviceEntity d WHERE d.tenantId = :tenantId " + - "AND d.edgeId = :edgeId " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:searchText, '%')) " + - "AND d.id > :idOffset ORDER BY d.id") - List findByTenantIdAndEdgeId(@Param("tenantId") String tenantId, - @Param("edgeId") String edgeId, - @Param("searchText") String searchText, - @Param("idOffset") String idOffset, - Pageable pageable); - - @Query("SELECT d FROM DeviceEntity d WHERE d.tenantId = :tenantId " + - "AND d.edgeId = :edgeId " + - "AND d.type = :type " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " + - "AND d.id > :idOffset ORDER BY d.id") - List findByTenantIdAndEdgeIdAndType(@Param("tenantId") String tenantId, - @Param("edgeId") String edgeId, - @Param("type") String type, - @Param("textSearch") String textSearch, - @Param("idOffset") String idOffset, - Pageable pageable); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java index 046db07e65..9b68493532 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java @@ -15,7 +15,10 @@ */ package org.thingsboard.server.dao.sql.device; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.PageRequest; import org.springframework.data.repository.CrudRepository; @@ -25,11 +28,17 @@ import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.UUIDConverter; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.page.TimePageLink; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.device.DeviceDao; import org.thingsboard.server.dao.model.sql.DeviceEntity; +import org.thingsboard.server.dao.relation.RelationDao; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; import org.thingsboard.server.dao.util.SqlDao; @@ -49,11 +58,15 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID_STR; */ @Component @SqlDao +@Slf4j public class JpaDeviceDao extends JpaAbstractSearchTextDao implements DeviceDao { @Autowired private DeviceRepository deviceRepository; + @Autowired + private RelationDao relationDao; + @Override protected Class getEntityClass() { return DeviceEntity.class; @@ -149,28 +162,16 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao return list; } - @Override - public List findDevicesByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink) { - return DaoUtil.convertDataList( - deviceRepository.findByTenantIdAndEdgeId( - fromTimeUUID(tenantId), - fromTimeUUID(edgeId), - Objects.toString(pageLink.getTextSearch(), ""), - pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), - PageRequest.of(0, pageLink.getLimit()))); - } - - @Override - public List findDevicesByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink) { - return DaoUtil.convertDataList( - deviceRepository.findByTenantIdAndEdgeIdAndType( - fromTimeUUID(tenantId), - fromTimeUUID(edgeId), - type, - Objects.toString(pageLink.getTextSearch(), ""), - pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), - PageRequest.of(0, pageLink.getLimit()))); + public ListenableFuture> findDevicesByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink) { + log.debug("Try to find devices by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink); + ListenableFuture> relations = relationDao.findRelations(new TenantId(tenantId), new EdgeId(edgeId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE, EntityType.DEVICE, pageLink); + return Futures.transformAsync(relations, input -> { + List> deviceFutures = new ArrayList<>(input.size()); + for (EntityRelation relation : input) { + deviceFutures.add(findByIdAsync(new TenantId(tenantId), relation.getTo().getId())); + } + return Futures.successfulAsList(deviceFutures); + }, MoreExecutors.directExecutor()); } - } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java index d5b8293de6..bc246e7dcc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java @@ -76,26 +76,4 @@ public interface EntityViewRepository extends CrudRepository findTenantEntityViewTypes(@Param("tenantId") String tenantId); - - @Query("SELECT e FROM EntityViewEntity e WHERE e.tenantId = :tenantId " + - "AND e.edgeId = :edgeId " + - "AND LOWER(e.searchText) LIKE LOWER(CONCAT(:searchText, '%')) " + - "AND e.id > :idOffset ORDER BY e.id") - List findByTenantIdAndEdgeId(@Param("tenantId") String tenantId, - @Param("edgeId") String edgeId, - @Param("searchText") String searchText, - @Param("idOffset") String idOffset, - Pageable pageable); - - @Query("SELECT e FROM EntityViewEntity e WHERE e.tenantId = :tenantId " + - "AND e.edgeId = :edgeId " + - "AND e.type = :type " + - "AND LOWER(e.searchText) LIKE LOWER(CONCAT(:searchText, '%')) " + - "AND e.id > :idOffset ORDER BY e.id") - List findByTenantIdAndEdgeIdAndType(@Param("tenantId") String tenantId, - @Param("edgeId") String edgeId, - @Param("type") String type, - @Param("searchText") String searchText, - @Param("idOffset") String idOffset, - Pageable pageable); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java index eed482fabd..a981fff90f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java @@ -15,20 +15,29 @@ */ package org.thingsboard.server.dao.sql.entityview; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.PageRequest; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.UUIDConverter; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.page.TimePageLink; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.entityview.EntityViewDao; import org.thingsboard.server.dao.model.sql.EntityViewEntity; +import org.thingsboard.server.dao.relation.RelationDao; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; import org.thingsboard.server.dao.util.SqlDao; @@ -47,12 +56,16 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID_STR; */ @Component @SqlDao +@Slf4j public class JpaEntityViewDao extends JpaAbstractSearchTextDao implements EntityViewDao { @Autowired private EntityViewRepository entityViewRepository; + @Autowired + private RelationDao relationDao; + @Override protected Class getEntityClass() { return EntityViewEntity.class; @@ -140,30 +153,15 @@ public class JpaEntityViewDao extends JpaAbstractSearchTextDao findEntityViewsByTenantIdAndEdgeId(UUID tenantId, - UUID edgeId, - TextPageLink pageLink) { - return DaoUtil.convertDataList( - entityViewRepository.findByTenantIdAndEdgeId( - fromTimeUUID(tenantId), - fromTimeUUID(edgeId), - Objects.toString(pageLink.getTextSearch(), ""), - pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), - PageRequest.of(0, pageLink.getLimit()) - )); - } - - @Override - public List findEntityViewsByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink) { - return DaoUtil.convertDataList( - entityViewRepository.findByTenantIdAndEdgeIdAndType( - fromTimeUUID(tenantId), - fromTimeUUID(edgeId), - type, - Objects.toString(pageLink.getTextSearch(), ""), - pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), - PageRequest.of(0, pageLink.getLimit()) - )); + public ListenableFuture> findEntityViewsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink) { + log.debug("Try to find entity views by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink); + ListenableFuture> relations = relationDao.findRelations(new TenantId(tenantId), new EdgeId(edgeId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE, EntityType.ENTITY_VIEW, pageLink); + return Futures.transformAsync(relations, input -> { + List> entityViewFutures = new ArrayList<>(input.size()); + for (EntityRelation relation : input) { + entityViewFutures.add(findByIdAsync(new TenantId(tenantId), relation.getTo().getId())); + } + return Futures.successfulAsList(entityViewFutures); + }, MoreExecutors.directExecutor()); } - } diff --git a/dao/src/main/resources/sql/schema-entities-hsql.sql b/dao/src/main/resources/sql/schema-entities-hsql.sql index 3930f428f0..42f52a2184 100644 --- a/dao/src/main/resources/sql/schema-entities-hsql.sql +++ b/dao/src/main/resources/sql/schema-entities-hsql.sql @@ -42,7 +42,6 @@ CREATE TABLE IF NOT EXISTS asset ( id varchar(31) NOT NULL CONSTRAINT asset_pkey PRIMARY KEY, additional_info varchar, customer_id varchar(31), - edge_id varchar(31), name varchar(255), label varchar(255), search_text varchar(255), @@ -120,7 +119,6 @@ CREATE TABLE IF NOT EXISTS device ( id varchar(31) NOT NULL CONSTRAINT device_pkey PRIMARY KEY, additional_info varchar, customer_id varchar(31), - edge_id varchar(31), type varchar(255), name varchar(255), label varchar(255), @@ -247,7 +245,6 @@ CREATE TABLE IF NOT EXISTS entity_view ( entity_type varchar(255), tenant_id varchar(31), customer_id varchar(31), - edge_id varchar(31), type varchar(255), name varchar(255), keys varchar(10000000), diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 10746084ae..ffea8bdf39 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -42,7 +42,6 @@ CREATE TABLE IF NOT EXISTS asset ( id varchar(31) NOT NULL CONSTRAINT asset_pkey PRIMARY KEY, additional_info varchar, customer_id varchar(31), - edge_id varchar(31), name varchar(255), label varchar(255), search_text varchar(255), @@ -120,7 +119,6 @@ CREATE TABLE IF NOT EXISTS device ( id varchar(31) NOT NULL CONSTRAINT device_pkey PRIMARY KEY, additional_info varchar, customer_id varchar(31), - edge_id varchar(31), type varchar(255), name varchar(255), label varchar(255), @@ -247,7 +245,6 @@ CREATE TABLE IF NOT EXISTS entity_view ( entity_type varchar(255), tenant_id varchar(31), customer_id varchar(31), - edge_id varchar(31), type varchar(255), name varchar(255), keys varchar(10000000), diff --git a/ui/src/app/api/asset.service.js b/ui/src/app/api/asset.service.js index c9ba3b1775..86d06670c9 100644 --- a/ui/src/app/api/asset.service.js +++ b/ui/src/app/api/asset.service.js @@ -18,7 +18,7 @@ export default angular.module('thingsboard.api.asset', []) .name; /*@ngInject*/ -function AssetService($http, $q, customerService, userService) { +function AssetService($http, $q, $filter, customerService, userService) { var service = { getAsset: getAsset, @@ -307,9 +307,9 @@ function AssetService($http, $q, customerService, userService) { return deferred.promise; } - function unassignAssetFromEdge(assetId, ignoreErrors, config) { + function unassignAssetFromEdge(edgeId, assetId, ignoreErrors, config) { var deferred = $q.defer(); - var url = '/api/edge/asset/' + assetId; + var url = '/api/edge/' + edgeId + '/asset/' + assetId; if (!config) { config = {}; } @@ -325,24 +325,20 @@ function AssetService($http, $q, customerService, userService) { function getEdgeAssets(edgeId, pageLink, config, type) { var deferred = $q.defer(); var url = '/api/edge/' + edgeId + '/assets?limit=' + pageLink.limit; - if (angular.isDefined(pageLink.textSearch)) { - url += '&textSearch=' + pageLink.textSearch; - } if (angular.isDefined(pageLink.idOffset)) { - url += '&idOffset=' + pageLink.idOffset; - } - if (angular.isDefined(pageLink.textOffset)) { - url += '&textOffset=' + pageLink.textOffset; - } - if (angular.isDefined(type) && type.length) { - url += '&type=' + type; + url += '&offset=' + pageLink.idOffset; } $http.get(url, config).then(function success(response) { + if (pageLink.textSearch) { + response.data.data = $filter('filter')(response.data.data, {name: pageLink.textSearch}); + } + if (angular.isDefined(type) && type.length) { + response.data.data = $filter('filter')(response.data.data, {type: type}); + } deferred.resolve(response.data); }, function fail() { deferred.reject(); }); - return deferred.promise; } } diff --git a/ui/src/app/api/device.service.js b/ui/src/app/api/device.service.js index 292e507cd3..9cc4412e86 100644 --- a/ui/src/app/api/device.service.js +++ b/ui/src/app/api/device.service.js @@ -20,7 +20,7 @@ export default angular.module('thingsboard.api.device', [thingsboardTypes]) .name; /*@ngInject*/ -function DeviceService($http, $q, $window, userService, attributeService, customerService, types) { +function DeviceService($http, $q, $window, $filter, userService, attributeService, customerService, types) { var service = { assignDeviceToCustomer: assignDeviceToCustomer, @@ -373,9 +373,9 @@ function DeviceService($http, $q, $window, userService, attributeService, custom return deferred.promise; } - function unassignDeviceFromEdge(deviceId) { + function unassignDeviceFromEdge(edgeId, deviceId) { var deferred = $q.defer(); - var url = '/api/edge/device/' + deviceId; + var url = '/api/edge/' + edgeId + '/device/' + deviceId; $http.delete(url).then(function success(response) { deferred.resolve(response.data); }, function fail() { @@ -387,25 +387,20 @@ function DeviceService($http, $q, $window, userService, attributeService, custom function getEdgeDevices(edgeId, pageLink, config, type) { var deferred = $q.defer(); var url = '/api/edge/' + edgeId + '/devices?limit=' + pageLink.limit; - if (angular.isDefined(pageLink.textSearch)) { - url += '&textSearch=' + pageLink.textSearch; - } if (angular.isDefined(pageLink.idOffset)) { - url += '&idOffset=' + pageLink.idOffset; - } - if (angular.isDefined(pageLink.textOffset)) { - url += '&textOffset=' + pageLink.textOffset; - } - if (angular.isDefined(type) && type.length) { - url += '&type=' + type; + url += '&offset=' + pageLink.idOffset; } $http.get(url, config).then(function success(response) { + if (pageLink.textSearch) { + response.data.data = $filter('filter')(response.data.data, {name: pageLink.textSearch}); + } + if (angular.isDefined(type) && type.length) { + response.data.data = $filter('filter')(response.data.data, {type: type}); + } deferred.resolve(response.data); }, function fail() { deferred.reject(); }); - return deferred.promise; } - } diff --git a/ui/src/app/api/entity-view.service.js b/ui/src/app/api/entity-view.service.js index ed5abc5752..cef08001cd 100644 --- a/ui/src/app/api/entity-view.service.js +++ b/ui/src/app/api/entity-view.service.js @@ -20,7 +20,7 @@ export default angular.module('thingsboard.api.entityView', [thingsboardTypes]) .name; /*@ngInject*/ -function EntityViewService($http, $q, $window, userService, attributeService, customerService, types) { +function EntityViewService($http, $q, $window, $filter, userService, attributeService, customerService, types) { var service = { assignEntityViewToCustomer: assignEntityViewToCustomer, @@ -234,9 +234,9 @@ function EntityViewService($http, $q, $window, userService, attributeService, cu return deferred.promise; } - function unassignEntityViewFromEdge(entityViewId) { + function unassignEntityViewFromEdge(edgeId, entityViewId) { var deferred = $q.defer(); - var url = '/api/edge/entityView/' + entityViewId; + var url = '/api/edge/' + edgeId + '/entityView/' + entityViewId; $http.delete(url).then(function success(response) { deferred.resolve(response.data); }, function fail() { @@ -248,24 +248,20 @@ function EntityViewService($http, $q, $window, userService, attributeService, cu function getEdgeEntityViews(edgeId, pageLink, config, type) { var deferred = $q.defer(); var url = '/api/edge/' + edgeId + '/entityViews?limit=' + pageLink.limit; - if (angular.isDefined(pageLink.textSearch)) { - url += '&textSearch=' + pageLink.textSearch; - } if (angular.isDefined(pageLink.idOffset)) { - url += '&idOffset=' + pageLink.idOffset; - } - if (angular.isDefined(pageLink.textOffset)) { - url += '&textOffset=' + pageLink.textOffset; - } - if (angular.isDefined(type) && type.length) { - url += '&type=' + type; + url += '&offset=' + pageLink.idOffset; } $http.get(url, config).then(function success(response) { + if (pageLink.textSearch) { + response.data.data = $filter('filter')(response.data.data, {name: pageLink.textSearch}); + } + if (angular.isDefined(type) && type.length) { + response.data.data = $filter('filter')(response.data.data, {type: type}); + } deferred.resolve(response.data); }, function fail() { deferred.reject(); }); - return deferred.promise; } } diff --git a/ui/src/app/asset/asset.controller.js b/ui/src/app/asset/asset.controller.js index d863133d4f..27190f18eb 100644 --- a/ui/src/app/asset/asset.controller.js +++ b/ui/src/app/asset/asset.controller.js @@ -327,7 +327,7 @@ export function AssetController($rootScope, userService, assetService, customerS return assetService.getEdgeAssets(edgeId, pageLink, null, assetType); }; deleteAssetFunction = function (assetId) { - return assetService.unassignAssetFromEdge(assetId); + return assetService.unassignAssetFromEdge(edgeId, assetId); }; refreshAssetsParamsFunction = function () { return {"edgeId": edgeId, "topIndex": vm.topIndex}; @@ -630,7 +630,7 @@ export function AssetController($rootScope, userService, assetService, customerS .cancel($translate.instant('action.no')) .ok($translate.instant('action.yes')); $mdDialog.show(confirm).then(function () { - assetService.unassignAssetFromEdge(asset.id.id).then(function success() { + assetService.unassignAssetFromEdge(edgeId, asset.id.id).then(function success() { vm.grid.refreshList(); }); }); @@ -639,15 +639,15 @@ export function AssetController($rootScope, userService, assetService, customerS function unassignAssetsFromEdge($event, items) { var confirm = $mdDialog.confirm() .targetEvent($event) - .title($translate.instant('asset.unassign-assets-title', {count: items.selectedCount}, 'messageformat')) - .htmlContent($translate.instant('asset.unassign-assets-text')) - .ariaLabel($translate.instant('asset.unassign-asset')) + .title($translate.instant('asset.unassign-assets-from-edge-title', {count: items.selectedCount}, 'messageformat')) + .htmlContent($translate.instant('asset.unassign-assets-from-edge-text')) + .ariaLabel($translate.instant('asset.unassign-asset-from-edge')) .cancel($translate.instant('action.no')) .ok($translate.instant('action.yes')); $mdDialog.show(confirm).then(function () { var tasks = []; for (var id in items.selections) { - tasks.push(assetService.unassignAssetFromEdge(id)); + tasks.push(assetService.unassignAssetFromEdge(edgeId, id)); } $q.all(tasks).then(function () { vm.grid.refreshList(); diff --git a/ui/src/app/device/device.controller.js b/ui/src/app/device/device.controller.js index 93f8dad1c4..05f7b54226 100644 --- a/ui/src/app/device/device.controller.js +++ b/ui/src/app/device/device.controller.js @@ -360,7 +360,7 @@ export function DeviceController($rootScope, userService, deviceService, custome return deviceService.getEdgeDevices(edgeId, pageLink, null, deviceType); }; deleteDeviceFunction = function (deviceId) { - return deviceService.unassignDeviceFromEdge(deviceId); + return deviceService.unassignDeviceFromEdge(edgeId, deviceId); }; refreshDevicesParamsFunction = function () { return {"edgeId": edgeId, "topIndex": vm.topIndex}; @@ -679,7 +679,7 @@ export function DeviceController($rootScope, userService, deviceService, custome .cancel($translate.instant('action.no')) .ok($translate.instant('action.yes')); $mdDialog.show(confirm).then(function () { - deviceService.unassignDeviceFromEdge(device.id.id).then(function success() { + deviceService.unassignDeviceFromEdge(edgeId, device.id.id).then(function success() { vm.grid.refreshList(); }); }); @@ -688,15 +688,15 @@ export function DeviceController($rootScope, userService, deviceService, custome function unassignDevicesFromEdge($event, items) { var confirm = $mdDialog.confirm() .targetEvent($event) - .title($translate.instant('device.unassign-devices-title', {count: items.selectedCount}, 'messageformat')) - .htmlContent($translate.instant('device.unassign-devices-text')) - .ariaLabel($translate.instant('device.unassign-device')) + .title($translate.instant('device.unassign-devices-from-edge-title', {count: items.selectedCount}, 'messageformat')) + .htmlContent($translate.instant('device.unassign-devices-from-edge-text')) + .ariaLabel($translate.instant('device.unassign-device-from-edge')) .cancel($translate.instant('action.no')) .ok($translate.instant('action.yes')); $mdDialog.show(confirm).then(function () { var tasks = []; for (var id in items.selections) { - tasks.push(deviceService.unassignDeviceFromEdge(id)); + tasks.push(deviceService.unassignDeviceFromEdge(edgeId, id)); } $q.all(tasks).then(function () { vm.grid.refreshList(); diff --git a/ui/src/app/entity-view/entity-view.controller.js b/ui/src/app/entity-view/entity-view.controller.js index 9c5e7907f5..3d382346de 100644 --- a/ui/src/app/entity-view/entity-view.controller.js +++ b/ui/src/app/entity-view/entity-view.controller.js @@ -288,7 +288,7 @@ export function EntityViewController($rootScope, userService, entityViewService, return entityViewService.getEdgeEntityViews(edgeId, pageLink, null, entityViewType); }; deleteEntityViewFunction = function (entityViewId) { - return entityViewService.unassignEntityViewFromEdge(entityViewId); + return entityViewService.unassignEntityViewFromEdge(edgeId, entityViewId); }; refreshEntityViewsParamsFunction = function () { return {"edgeId": edgeId, "topIndex": vm.topIndex}; @@ -300,10 +300,7 @@ export function EntityViewController($rootScope, userService, entityViewService, }, name: function() { return $translate.instant('action.unassign') }, details: function() { return $translate.instant('entity-view.unassign-from-edge') }, - icon: "assignment_return", - isEnabled: function(entityView) { - return entityView && entityView.edgeId && entityView.edgeId.id !== types.id.nullUid; - } + icon: "assignment_return" } ); @@ -314,7 +311,7 @@ export function EntityViewController($rootScope, userService, entityViewService, }, name: function() { return $translate.instant('entity-view.unassign-entity-views') }, details: function(selectedCount) { - return $translate.instant('entity-view.unassign-entity-views-action-title', {count: selectedCount}, "messageformat"); + return $translate.instant('entity-view.unassign-entity-views-from-edge-action-title', {count: selectedCount}, "messageformat"); }, icon: "assignment_return" } @@ -581,15 +578,15 @@ export function EntityViewController($rootScope, userService, entityViewService, function unassignEntityViewsFromEdge($event, items) { var confirm = $mdDialog.confirm() .targetEvent($event) - .title($translate.instant('entity-view.unassign-entity-views-title', {count: items.selectedCount}, 'messageformat')) - .htmlContent($translate.instant('entity-view.unassign-entity-views-text')) - .ariaLabel($translate.instant('entity-view.unassign-entity-view')) + .title($translate.instant('entity-view.unassign-entity-views-from-edge-title', {count: items.selectedCount}, 'messageformat')) + .htmlContent($translate.instant('entity-view.unassign-entity-views-from-edge-text')) + .ariaLabel($translate.instant('entity-view.unassign-entity-view-from-edge')) .cancel($translate.instant('action.no')) .ok($translate.instant('action.yes')); $mdDialog.show(confirm).then(function () { var tasks = []; for (var id in items.selections) { - tasks.push(entityViewService.unassignEntityViewFromEdge(id)); + tasks.push(entityViewService.unassignEntityViewFromEdge(edgeId, id)); } $q.all(tasks).then(function () { vm.grid.refreshList(); @@ -612,7 +609,7 @@ export function EntityViewController($rootScope, userService, entityViewService, .cancel($translate.instant('action.no')) .ok($translate.instant('action.yes')); $mdDialog.show(confirm).then(function () { - entityViewService.unassignEntityViewFromEdge(entityView.id.id).then(function success() { + entityViewService.unassignEntityViewFromEdge(edgeId, entityView.id.id).then(function success() { vm.grid.refreshList(); }); }); diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json index 1fbb81066e..1688b59692 100644 --- a/ui/src/app/locale/locale.constant-en_US.json +++ b/ui/src/app/locale/locale.constant-en_US.json @@ -291,9 +291,12 @@ "unassign-from-edge": "Unassign from edge", "assign-to-edge": "Assign to edge", "assign-to-edge-text": "Please select the edge to assign the asset(s)", + "unassign-asset-from-edge": "Unassign asset", "unassign-asset-from-edge-title": "Are you sure you want to unassign the asset '{{assetName}}'?", "unassign-asset-from-edge-text": "After the confirmation the asset will be unassigned and won't be accessible by the edge.", - "unassign-assets-from-edge-action-title": "Unassign { count, plural, 1 {1 asset} other {# assets} } from edge" + "unassign-assets-from-edge-action-title": "Unassign { count, plural, 1 {1 asset} other {# assets} } from edge", + "unassign-assets-from-edge-title": "Are you sure you want to unassign { count, plural, 1 {1 asset} other {# assets} }?", + "unassign-assets-from-edge-text": "After the confirmation all selected assets will be unassigned and won't be accessible by the edge." }, "attribute": { "attributes": "Attributes", @@ -748,7 +751,10 @@ "assign-to-edge-text": "Please select the edge to assign the device(s)", "unassign-device-from-edge-title": "Are you sure you want to unassign the device '{{deviceName}}'?", "unassign-device-from-edge-text": "After the confirmation the device will be unassigned and won't be accessible by the edge.", - "unassign-devices-from-edge-action-title": "Unassign { count, plural, 1 {1 device} other {# devices} } from edge" + "unassign-devices-from-edge-action-title": "Unassign { count, plural, 1 {1 device} other {# devices} } from edge", + "unassign-device-from-edge": "Unassign device", + "unassign-devices-from-edge-title": "Are you sure you want to unassign { count, plural, 1 {1 device} other {# devices} }?", + "unassign-devices-from-edge-text": "After the confirmation all selected devices will be unassigned and won't be accessible by the edge." }, "dialog": { "close": "Close dialog" @@ -1054,7 +1060,10 @@ "assign-to-edge-text": "Please select the edge to assign the entity view(s)", "unassign-entity-view-from-edge-title": "Are you sure you want to unassign the entity view '{{entityViewName}}'?", "unassign-entity-view-from-edge-text": "After the confirmation the entity view will be unassigned and won't be accessible by the edge.", - "unassign-entity-views-from-edge-action-title": "Unassign { count, plural, 1 {1 entity view} other {# entity views} } from edge" + "unassign-entity-views-from-edge-action-title": "Unassign { count, plural, 1 {1 entity view} other {# entity views} } from edge", + "unassign-entity-view-from-edge": "Unassign entity view", + "unassign-entity-views-from-edge-title": "Are you sure you want to unassign { count, plural, 1 {1 entity view} other {# entity views} }?", + "unassign-entity-views-from-edge-text": "After the confirmation all selected entity views will be unassigned and won't be accessible by the edge." }, "event": { "event-type": "Event type", @@ -1580,7 +1589,7 @@ "invalid-rulechain-type-error": "Unable to import rule chain: Invalid rule chain type. Expected type is {{expectedRuleChainType}}.", "set-default-edge": "Make edge rule chain default", "set-default-edge-title": "Are you sure you want to make the edge rule chain '{{ruleChainName}}' default?", - "set-default-edge-text": "After the confirmation the edge rule chain will be added to default list and handle all incoming transport messages.", + "set-default-edge-text": "After the confirmation the edge rule chain will be added to default list and assigned to newly created edge(s).", "remove-default-edge": "Remove edge rule chain from defaults", "remove-default-edge-title": "Are you sure you want to remove the edge rule chain '{{ruleChainName}}' from default list?", "remove-default-edge-text": "After the confirmation the edge rule chain will stop handling all incoming transport messages."