Commit 009da885ad9486ffaa29325c7349f627d51fdf86

Authored by VoBa
Committed by GitHub
2 parents b0b6ee06 ae8d8f01

Merge pull request #1043 from ViktorBasanets/master

Entity View
... ... @@ -24,6 +24,7 @@ DROP TABLE IF EXISTS thingsboard.entity_views;
24 24 CREATE TABLE IF NOT EXISTS thingsboard.entity_views (
25 25 id timeuuid,
26 26 entity_id timeuuid,
  27 + entity_type text,
27 28 tenant_id timeuuid,
28 29 customer_id timeuuid,
29 30 name text,
... ... @@ -33,7 +34,7 @@ CREATE TABLE IF NOT EXISTS thingsboard.entity_views (
33 34 search_text text,
34 35 additional_info text,
35 36 PRIMARY KEY (id, entity_id, tenant_id, customer_id)
36   - );
  37 +);
37 38
38 39 CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_name AS
39 40 SELECT *
... ...
... ... @@ -26,17 +26,11 @@ import org.springframework.stereotype.Component;
26 26 import org.springframework.web.context.request.async.DeferredResult;
27 27 import org.thingsboard.server.common.data.Customer;
28 28 import org.thingsboard.server.common.data.Device;
  29 +import org.thingsboard.server.common.data.EntityView;
29 30 import org.thingsboard.server.common.data.Tenant;
30 31 import org.thingsboard.server.common.data.asset.Asset;
31 32 import org.thingsboard.server.common.data.exception.ThingsboardException;
32   -import org.thingsboard.server.common.data.id.AssetId;
33   -import org.thingsboard.server.common.data.id.CustomerId;
34   -import org.thingsboard.server.common.data.id.DeviceId;
35   -import org.thingsboard.server.common.data.id.EntityId;
36   -import org.thingsboard.server.common.data.id.EntityIdFactory;
37   -import org.thingsboard.server.common.data.id.RuleChainId;
38   -import org.thingsboard.server.common.data.id.RuleNodeId;
39   -import org.thingsboard.server.common.data.id.TenantId;
  33 +import org.thingsboard.server.common.data.id.*;
40 34 import org.thingsboard.server.common.data.rule.RuleChain;
41 35 import org.thingsboard.server.common.data.rule.RuleNode;
42 36 import org.thingsboard.server.controller.HttpValidationCallback;
... ... @@ -44,6 +38,7 @@ import org.thingsboard.server.dao.alarm.AlarmService;
44 38 import org.thingsboard.server.dao.asset.AssetService;
45 39 import org.thingsboard.server.dao.customer.CustomerService;
46 40 import org.thingsboard.server.dao.device.DeviceService;
  41 +import org.thingsboard.server.dao.entityview.EntityViewService;
47 42 import org.thingsboard.server.dao.rule.RuleChainService;
48 43 import org.thingsboard.server.dao.tenant.TenantService;
49 44 import org.thingsboard.server.dao.user.UserService;
... ... @@ -66,6 +61,7 @@ public class AccessValidator {
66 61 public static final String CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "Customer user is not allowed to perform this operation!";
67 62 public static final String SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "System administrator is not allowed to perform this operation!";
68 63 public static final String DEVICE_WITH_REQUESTED_ID_NOT_FOUND = "Device with requested id wasn't found!";
  64 + public static final String ENTITY_VIEW_WITH_REQUESTED_ID_NOT_FOUND = "Entity-view with requested id wasn't found!";
69 65
70 66 @Autowired
71 67 protected TenantService tenantService;
... ... @@ -88,6 +84,9 @@ public class AccessValidator {
88 84 @Autowired
89 85 protected RuleChainService ruleChainService;
90 86
  87 + @Autowired
  88 + protected EntityViewService entityViewService;
  89 +
91 90 private ExecutorService executor;
92 91
93 92 @PostConstruct
... ... @@ -158,6 +157,9 @@ public class AccessValidator {
158 157 case TENANT:
159 158 validateTenant(currentUser, entityId, callback);
160 159 return;
  160 + case ENTITY_VIEW:
  161 + validateEntityView(currentUser, entityId, callback);
  162 + return;
161 163 default:
162 164 //TODO: add support of other entities
163 165 throw new IllegalStateException("Not Implemented!");
... ... @@ -293,6 +295,27 @@ public class AccessValidator {
293 295 }
294 296 }
295 297
  298 + private void validateEntityView(final SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) {
  299 + if (currentUser.isSystemAdmin()) {
  300 + callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
  301 + } else {
  302 + ListenableFuture<EntityView> entityViewFuture = entityViewService.findEntityViewByIdAsync(new EntityViewId(entityId.getId()));
  303 + Futures.addCallback(entityViewFuture, getCallback(callback, entityView -> {
  304 + if (entityView == null) {
  305 + return ValidationResult.entityNotFound(ENTITY_VIEW_WITH_REQUESTED_ID_NOT_FOUND);
  306 + } else {
  307 + if (!entityView.getTenantId().equals(currentUser.getTenantId())) {
  308 + return ValidationResult.accessDenied("Entity-view doesn't belong to the current Tenant!");
  309 + } else if (currentUser.isCustomerUser() && !entityView.getCustomerId().equals(currentUser.getCustomerId())) {
  310 + return ValidationResult.accessDenied("Entity-view doesn't belong to the current Customer!");
  311 + } else {
  312 + return ValidationResult.ok(entityView);
  313 + }
  314 + }
  315 + }), executor);
  316 + }
  317 + }
  318 +
296 319 private <T, V> FutureCallback<T> getCallback(FutureCallback<ValidationResult> callback, Function<T, ValidationResult<V>> transformer) {
297 320 return new FutureCallback<T>() {
298 321 @Override
... ...
... ... @@ -24,7 +24,7 @@ import java.util.Arrays;
24 24
25 25 @RunWith(ClasspathSuite.class)
26 26 @ClasspathSuite.ClassnameFilters({
27   - "org.thingsboard.server.controller.sql.EntityViewControllerSqlTest",
  27 + "org.thingsboard.server.controller.sql.*Test",
28 28 })
29 29 public class ControllerSqlTestSuite {
30 30
... ...
... ... @@ -16,9 +16,11 @@
16 16 package org.thingsboard.server.controller.nosql;
17 17
18 18 import org.thingsboard.server.controller.BaseEntityViewControllerTest;
  19 +import org.thingsboard.server.dao.service.DaoNoSqlTest;
19 20
20 21 /**
21 22 * Created by Victor Basanets on 8/27/2017.
22 23 */
  24 +@DaoNoSqlTest
23 25 public class EntityViewControllerNoSqlTest extends BaseEntityViewControllerTest {
24 26 }
... ...
... ... @@ -39,8 +39,8 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo<EntityViewId>
39 39 private CustomerId customerId;
40 40 private String name;
41 41 private TelemetryEntityView keys;
42   - private Long tsBegin;
43   - private Long tsEnd;
  42 + private long startTs;
  43 + private long endTs;
44 44
45 45 public EntityView() {
46 46 super();
... ...
... ... @@ -44,9 +44,4 @@ public class AttributesEntityView {
44 44 public AttributesEntityView(AttributesEntityView obj) {
45 45 this(obj.getCs(), obj.getSs(), obj.getSh());
46 46 }
47   -
48   - @Override
49   - public String toString() {
50   - return "{cs=" + cs + ", ss=" + ss + ", sh=" + sh + '}';
51   - }
52 47 }
... ...
... ... @@ -40,9 +40,4 @@ public class TelemetryEntityView {
40 40 public TelemetryEntityView(TelemetryEntityView obj) {
41 41 this(obj.getTimeseries(), obj.getAttributes());
42 42 }
43   -
44   - @Override
45   - public String toString() {
46   - return "{timeseries=" + timeseries + ", attributes=" + attributes + '}';
47   - }
48 43 }
... ...
  1 +/**
  2 + * Copyright © 2016-2018 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.entityview;
  17 +
  18 +import com.datastax.driver.core.Statement;
  19 +import com.datastax.driver.core.querybuilder.Select;
  20 +import lombok.extern.slf4j.Slf4j;
  21 +import org.springframework.stereotype.Component;
  22 +import org.thingsboard.server.common.data.EntitySubtype;
  23 +import org.thingsboard.server.common.data.EntityType;
  24 +import org.thingsboard.server.common.data.EntityView;
  25 +import org.thingsboard.server.common.data.page.TextPageLink;
  26 +import org.thingsboard.server.dao.DaoUtil;
  27 +import org.thingsboard.server.dao.model.EntitySubtypeEntity;
  28 +import org.thingsboard.server.dao.model.nosql.EntityViewEntity;
  29 +import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao;
  30 +import org.thingsboard.server.dao.util.NoSqlDao;
  31 +
  32 +import java.util.*;
  33 +
  34 +import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
  35 +import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
  36 +import static org.thingsboard.server.dao.model.ModelConstants.*;
  37 +
  38 +/**
  39 + * Created by Victor Basanets on 9/06/2017.
  40 + */
  41 +@Component
  42 +@Slf4j
  43 +@NoSqlDao
  44 +public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<EntityViewEntity, EntityView> implements EntityViewDao {
  45 +
  46 + @Override
  47 + protected Class<EntityViewEntity> getColumnFamilyClass() {
  48 + return EntityViewEntity.class;
  49 + }
  50 +
  51 + @Override
  52 + protected String getColumnFamilyName() {
  53 + return ENTITY_VIEW_TABLE_FAMILY_NAME;
  54 + }
  55 +
  56 + @Override
  57 + public EntityView save(EntityView domain) {
  58 + EntityView savedEntityView = super.save(domain);
  59 + EntitySubtype entitySubtype = new EntitySubtype(savedEntityView.getTenantId(), EntityType.ENTITY_VIEW,
  60 + savedEntityView.getId().getEntityType().toString());
  61 + EntitySubtypeEntity entitySubtypeEntity = new EntitySubtypeEntity(entitySubtype);
  62 + Statement saveStatement = cluster.getMapper(EntitySubtypeEntity.class).saveQuery(entitySubtypeEntity);
  63 + executeWrite(saveStatement);
  64 + return savedEntityView;
  65 + }
  66 +
  67 + @Override
  68 + public List<EntityView> findEntityViewByTenantId(UUID tenantId, TextPageLink pageLink) {
  69 + log.debug("Try to find entity-views by tenantId [{}] and pageLink [{}]", tenantId, pageLink);
  70 + List<EntityViewEntity> entityViewEntities =
  71 + findPageWithTextSearch(ENTITY_VIEW_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
  72 + Collections.singletonList(eq(ENTITY_VIEW_TENANT_ID_PROPERTY, tenantId)), pageLink);
  73 +
  74 + log.trace("Found entity-views [{}] by tenantId [{}] and pageLink [{}]", entityViewEntities, tenantId, pageLink);
  75 + return DaoUtil.convertDataList(entityViewEntities);
  76 + }
  77 +
  78 + @Override
  79 + public Optional<EntityView> findEntityViewByTenantIdAndName(UUID tenantId, String entityViewName) {
  80 + return Optional.ofNullable(DaoUtil.getData(
  81 + findOneByStatement(select().from(ENTITY_VIEW_TENANT_AND_NAME_VIEW_NAME).where()
  82 + .and(eq(ENTITY_VIEW_TENANT_ID_PROPERTY, tenantId))
  83 + .and(eq(ENTITY_VIEW_NAME_PROPERTY, entityViewName))))
  84 + );
  85 + }
  86 +
  87 + @Override
  88 + public List<EntityView> findEntityViewByTenantIdAndEntityId(UUID tenantId, UUID entityId, TextPageLink pageLink) {
  89 + log.debug("Try to find entity-views by tenantId [{}], entityId[{}] and pageLink [{}]", tenantId, entityId, pageLink);
  90 + List<EntityViewEntity> entityViewEntities = findPageWithTextSearch(DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
  91 + Arrays.asList(eq(DEVICE_CUSTOMER_ID_PROPERTY, entityId),
  92 + eq(DEVICE_TENANT_ID_PROPERTY, tenantId)),
  93 + pageLink);
  94 +
  95 + log.trace("Found entity-views [{}] by tenantId [{}], entityId [{}] and pageLink [{}]", entityViewEntities, tenantId, entityId, pageLink);
  96 + return DaoUtil.convertDataList(entityViewEntities);
  97 + }
  98 +
  99 + @Override
  100 + public List<EntityView> findEntityViewsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) {
  101 + return null;
  102 + }
  103 +
  104 + @Override
  105 + public List<EntityView> findEntityViewsByTenantIdAndCustomerIdAndEntityId(UUID tenantId, UUID customerId, UUID entityId, TextPageLink pageLink) {
  106 + return null;
  107 + }
  108 +}
... ...
... ... @@ -30,6 +30,14 @@ import java.util.UUID;
30 30 public interface EntityViewDao extends Dao<EntityView> {
31 31
32 32 /**
  33 + * Save or update device object
  34 + *
  35 + * @param entityView the entity-view object
  36 + * @return saved entity-view object
  37 + */
  38 + EntityView save(EntityView entityView);
  39 +
  40 + /**
33 41 * Find entity views by tenantId and page link.
34 42 *
35 43 * @param tenantId the tenantId
... ...
... ... @@ -15,12 +15,10 @@
15 15 */
16 16 package org.thingsboard.server.dao.entityview;
17 17
  18 +import com.google.common.util.concurrent.ListenableFuture;
18 19 import org.thingsboard.server.common.data.EntityType;
19 20 import org.thingsboard.server.common.data.EntityView;
20   -import org.thingsboard.server.common.data.id.CustomerId;
21   -import org.thingsboard.server.common.data.id.EntityId;
22   -import org.thingsboard.server.common.data.id.EntityViewId;
23   -import org.thingsboard.server.common.data.id.TenantId;
  21 +import org.thingsboard.server.common.data.id.*;
24 22 import org.thingsboard.server.common.data.page.TextPageData;
25 23 import org.thingsboard.server.common.data.page.TextPageLink;
26 24
... ... @@ -57,4 +55,6 @@ public interface EntityViewService {
57 55 TextPageLink pageLink);
58 56
59 57 void unassignCustomerEntityViews(TenantId tenantId, CustomerId customerId);
  58 +
  59 + ListenableFuture<EntityView> findEntityViewByIdAsync(EntityViewId entityViewId);
60 60 }
... ...
... ... @@ -15,11 +15,14 @@
15 15 */
16 16 package org.thingsboard.server.dao.entityview;
17 17
  18 +import com.google.common.util.concurrent.ListenableFuture;
18 19 import lombok.extern.slf4j.Slf4j;
19 20 import org.apache.commons.lang3.StringUtils;
20 21 import org.springframework.beans.factory.annotation.Autowired;
21 22 import org.springframework.cache.Cache;
22 23 import org.springframework.cache.CacheManager;
  24 +import org.springframework.cache.annotation.CacheEvict;
  25 +import org.springframework.cache.annotation.Cacheable;
23 26 import org.springframework.stereotype.Service;
24 27 import org.thingsboard.server.common.data.Customer;
25 28 import org.thingsboard.server.common.data.EntityView;
... ... @@ -40,6 +43,8 @@ import org.thingsboard.server.dao.tenant.TenantDao;
40 43 import java.util.ArrayList;
41 44 import java.util.List;
42 45
  46 +import static org.thingsboard.server.common.data.CacheConstants.DEVICE_CACHE;
  47 +import static org.thingsboard.server.common.data.CacheConstants.ENTITY_VIEW_CACHE;
43 48 import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
44 49 import static org.thingsboard.server.dao.service.Validator.validateId;
45 50 import static org.thingsboard.server.dao.service.Validator.validatePageLink;
... ... @@ -67,6 +72,10 @@ public class EntityViewServiceImpl extends AbstractEntityService
67 72 @Autowired
68 73 private CustomerDao customerDao;
69 74
  75 + @Autowired
  76 + private CacheManager cacheManager;
  77 +
  78 + @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}")
70 79 @Override
71 80 public EntityView findEntityViewById(EntityViewId entityViewId) {
72 81 log.trace("Executing findEntityViewById [{}]", entityViewId);
... ... @@ -82,6 +91,7 @@ public class EntityViewServiceImpl extends AbstractEntityService
82 91 .orElse(null);
83 92 }
84 93
  94 + @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityView.id}")
85 95 @Override
86 96 public EntityView saveEntityView(EntityView entityView) {
87 97 log.trace("Executing save entity view [{}]", entityView);
... ... @@ -106,12 +116,14 @@ public class EntityViewServiceImpl extends AbstractEntityService
106 116 @Override
107 117 public void deleteEntityView(EntityViewId entityViewId) {
108 118 log.trace("Executing deleteEntityView [{}]", entityViewId);
  119 + Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE);
109 120 validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId);
110 121 deleteEntityRelations(entityViewId);
111 122 EntityView entityView = entityViewDao.findById(entityViewId.getId());
112 123 List<Object> list = new ArrayList<>();
113 124 list.add(entityView.getTenantId());
114 125 list.add(entityView.getName());
  126 + cache.evict(list);
115 127 entityViewDao.removeById(entityViewId.getId());
116 128 }
117 129
... ... @@ -124,6 +136,7 @@ public class EntityViewServiceImpl extends AbstractEntityService
124 136 return new TextPageData<>(entityViews, pageLink);
125 137 }
126 138
  139 + @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #entityId, #pageLink}")
127 140 @Override
128 141 public TextPageData<EntityView> findEntityViewByTenantIdAndEntityId(TenantId tenantId, EntityId entityId,
129 142 TextPageLink pageLink) {
... ... @@ -163,6 +176,7 @@ public class EntityViewServiceImpl extends AbstractEntityService
163 176 return new TextPageData<>(entityViews, pageLink);
164 177 }
165 178
  179 + @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #customerId, #entityId, #pageLink}")
166 180 @Override
167 181 public TextPageData<EntityView> findEntityViewsByTenantIdAndCustomerIdAndEntityId(TenantId tenantId,
168 182 CustomerId customerId,
... ... @@ -190,6 +204,13 @@ public class EntityViewServiceImpl extends AbstractEntityService
190 204 new CustomerEntityViewsUnAssigner(tenantId).removeEntities(customerId);
191 205 }
192 206
  207 + @Override
  208 + public ListenableFuture<EntityView> findEntityViewByIdAsync(EntityViewId entityViewId) {
  209 + log.trace("Executing findEntityViewById [{}]", entityViewId);
  210 + validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId);
  211 + return entityViewDao.findByIdAsync(entityViewId.getId());
  212 + }
  213 +
193 214 private DataValidator<EntityView> entityViewValidator =
194 215 new DataValidator<EntityView>() {
195 216
... ...
... ... @@ -136,7 +136,6 @@ public class ModelConstants {
136 136 public static final String DEVICE_NAME_PROPERTY = "name";
137 137 public static final String DEVICE_TYPE_PROPERTY = "type";
138 138 public static final String DEVICE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
139   -
140 139 public static final String DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_and_search_text";
141 140 public static final String DEVICE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_by_type_and_search_text";
142 141 public static final String DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_customer_and_search_text";
... ... @@ -152,11 +151,12 @@ public class ModelConstants {
152 151 public static final String ENTITY_VIEW_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
153 152 public static final String ENTITY_VIEW_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY;
154 153 public static final String ENTITY_VIEW_NAME_PROPERTY = DEVICE_NAME_PROPERTY;
155   - public static final String ENTITY_VIEW_TYPE_PROPERTY = "type_entity";
  154 + public static final String ENTITY_VIEW_TENANT_AND_NAME_VIEW_NAME = "entity_view_by_tenant_and_name";
156 155 public static final String ENTITY_VIEW_KEYS_PROPERTY = "keys";
157 156 public static final String ENTITY_VIEW_TS_BEGIN_PROPERTY = "ts_begin";
158 157 public static final String ENTITY_VIEW_TS_END_PROPERTY = "ts_end";
159 158 public static final String ENTITY_VIEW_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
  159 + public static final String ENTITY_VIEW_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "entity_view_by_tenant_and_search_text";
160 160
161 161 /**
162 162 * Cassandra audit log constants.
... ...
... ... @@ -19,24 +19,26 @@ import com.datastax.driver.core.utils.UUIDs;
19 19 import com.datastax.driver.mapping.annotations.PartitionKey;
20 20 import com.datastax.driver.mapping.annotations.Table;
21 21 import com.fasterxml.jackson.databind.JsonNode;
  22 +import com.fasterxml.jackson.databind.ObjectMapper;
22 23 import lombok.Data;
23 24 import lombok.EqualsAndHashCode;
24 25 import lombok.ToString;
25 26 import org.hibernate.annotations.Type;
  27 +import org.thingsboard.server.common.data.EntityType;
26 28 import org.thingsboard.server.common.data.EntityView;
27   -import org.thingsboard.server.common.data.id.CustomerId;
28   -import org.thingsboard.server.common.data.id.DeviceId;
29   -import org.thingsboard.server.common.data.id.EntityViewId;
30   -import org.thingsboard.server.common.data.id.TenantId;
  29 +import org.thingsboard.server.common.data.id.*;
31 30 import org.thingsboard.server.common.data.objects.TelemetryEntityView;
32 31 import org.thingsboard.server.dao.model.ModelConstants;
33 32 import org.thingsboard.server.dao.model.SearchTextEntity;
34 33
35 34 import javax.persistence.Column;
  35 +import javax.persistence.EnumType;
  36 +import javax.persistence.Enumerated;
36 37
37 38 import java.io.IOException;
38 39 import java.util.UUID;
39 40
  41 +import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_TYPE_PROPERTY;
40 42 import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_TABLE_FAMILY_NAME;
41 43 import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY;
42 44
... ... @@ -57,6 +59,10 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
57 59 @Column(name = ModelConstants.ENTITY_VIEW_ENTITY_ID_PROPERTY)
58 60 private UUID entityId;
59 61
  62 + @Enumerated(EnumType.STRING)
  63 + @Column(name = ENTITY_TYPE_PROPERTY)
  64 + private EntityType entityType;
  65 +
60 66 @PartitionKey(value = 2)
61 67 @Column(name = ModelConstants.ENTITY_VIEW_TENANT_ID_PROPERTY)
62 68 private UUID tenantId;
... ... @@ -68,9 +74,8 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
68 74 @Column(name = ModelConstants.ENTITY_VIEW_NAME_PROPERTY)
69 75 private String name;
70 76
71   - @Type(type = "json")
72 77 @Column(name = ModelConstants.ENTITY_VIEW_KEYS_PROPERTY)
73   - private JsonNode keys;
  78 + private String keys;
74 79
75 80 @Column(name = ModelConstants.ENTITY_VIEW_TS_BEGIN_PROPERTY)
76 81 private String tsBegin;
... ... @@ -85,6 +90,8 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
85 90 @Column(name = ModelConstants.ENTITY_VIEW_ADDITIONAL_INFO_PROPERTY)
86 91 private JsonNode additionalInfo;
87 92
  93 + private static final ObjectMapper mapper = new ObjectMapper();
  94 +
88 95 public EntityViewEntity() {
89 96 super();
90 97 }
... ... @@ -95,6 +102,7 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
95 102 }
96 103 if (entityView.getEntityId() != null) {
97 104 this.entityId = entityView.getEntityId().getId();
  105 + this.entityType = entityView.getEntityId().getEntityType();
98 106 }
99 107 if (entityView.getTenantId() != null) {
100 108 this.tenantId = entityView.getTenantId().getId();
... ... @@ -103,13 +111,13 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
103 111 this.customerId = entityView.getCustomerId().getId();
104 112 }
105 113 this.name = entityView.getName();
106   -// try {
107   -// this.keys = entityView.getKeys();
108   -// } catch (IOException e) {
109   -// e.printStackTrace();
110   -// }
111   - this.tsBegin = entityView.getTsBegin() != null ? String.valueOf(entityView.getTsBegin()) : "0";
112   - this.tsEnd = entityView.getTsEnd() != null ? String.valueOf(entityView.getTsEnd()) : "0";
  114 + try {
  115 + this.keys = mapper.writeValueAsString(entityView.getKeys());
  116 + } catch (IOException e) {
  117 + e.printStackTrace();
  118 + }
  119 + this.tsBegin = entityView.getStartTs() != 0L ? String.valueOf(entityView.getStartTs()) : "0";
  120 + this.tsEnd = entityView.getEndTs() != 0L ? String.valueOf(entityView.getEndTs()) : "0";
113 121 this.searchText = entityView.getSearchText();
114 122 this.additionalInfo = entityView.getAdditionalInfo();
115 123 }
... ... @@ -124,7 +132,7 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
124 132 EntityView entityView = new EntityView(new EntityViewId(id));
125 133 entityView.setCreatedTime(UUIDs.unixTimestamp(id));
126 134 if (entityId != null) {
127   - entityView.setEntityId(new DeviceId(entityId));
  135 + entityView.setEntityId(EntityIdFactory.getByTypeAndId(entityType.name(), entityId.toString()));
128 136 }
129 137 if (tenantId != null) {
130 138 entityView.setTenantId(new TenantId(tenantId));
... ... @@ -133,13 +141,13 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
133 141 entityView.setCustomerId(new CustomerId(customerId));
134 142 }
135 143 entityView.setName(name);
136   -// try {
137   -// entityView.setKeys((TelemetryEntityView) entityView.getKeys().toObject(keys));
138   -// } catch (IOException e) {
139   -// e.printStackTrace();
140   -// }
141   - entityView.setTsBegin(Long.parseLong(tsBegin));
142   - entityView.setTsEnd(Long.parseLong(tsEnd));
  144 + try {
  145 + entityView.setKeys(mapper.readValue(keys, TelemetryEntityView.class));
  146 + } catch (IOException e) {
  147 + e.printStackTrace();
  148 + }
  149 + entityView.setStartTs(Long.parseLong(tsBegin));
  150 + entityView.setEndTs(Long.parseLong(tsEnd));
143 151 entityView.setAdditionalInfo(additionalInfo);
144 152 return entityView;
145 153 }
... ...
... ... @@ -34,7 +34,6 @@ import org.thingsboard.server.dao.util.mapping.JsonStringType;
34 34 import javax.persistence.*;
35 35 import java.io.IOException;
36 36
37   -import static org.thingsboard.server.dao.model.ModelConstants.AUDIT_LOG_ENTITY_TYPE_PROPERTY;
38 37 import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_TYPE_PROPERTY;
39 38
40 39 /**
... ... @@ -106,8 +105,8 @@ public class EntityViewEntity extends BaseSqlEntity<EntityView> implements Searc
106 105 } catch (IOException e) {
107 106 e.printStackTrace();
108 107 }
109   - this.tsBegin = entityView.getTsBegin() != null ? String.valueOf(entityView.getTsBegin()) : "0";
110   - this.tsEnd = entityView.getTsEnd() != null ? String.valueOf(entityView.getTsEnd()) : "0";
  108 + this.tsBegin = entityView.getStartTs() != 0L ? String.valueOf(entityView.getStartTs()) : "0";
  109 + this.tsEnd = entityView.getEndTs() != 0L ? String.valueOf(entityView.getEndTs()) : "0";
111 110 this.searchText = entityView.getSearchText();
112 111 this.additionalInfo = entityView.getAdditionalInfo();
113 112 }
... ... @@ -142,8 +141,8 @@ public class EntityViewEntity extends BaseSqlEntity<EntityView> implements Searc
142 141 } catch (IOException e) {
143 142 e.printStackTrace();
144 143 }
145   - entityView.setTsBegin(Long.parseLong(tsBegin));
146   - entityView.setTsEnd(Long.parseLong(tsEnd));
  144 + entityView.setStartTs(Long.parseLong(tsBegin));
  145 + entityView.setEndTs(Long.parseLong(tsEnd));
147 146 entityView.setAdditionalInfo(additionalInfo);
148 147 return entityView;
149 148 }
... ...
... ... @@ -21,12 +21,18 @@ import com.google.common.util.concurrent.ListenableFuture;
21 21 import lombok.extern.slf4j.Slf4j;
22 22 import org.springframework.beans.factory.annotation.Autowired;
23 23 import org.springframework.stereotype.Service;
  24 +import org.thingsboard.server.common.data.EntityType;
  25 +import org.thingsboard.server.common.data.EntityView;
24 26 import org.thingsboard.server.common.data.id.EntityId;
  27 +import org.thingsboard.server.common.data.id.EntityViewId;
  28 +import org.thingsboard.server.common.data.kv.BaseTsKvQuery;
25 29 import org.thingsboard.server.common.data.kv.TsKvEntry;
26 30 import org.thingsboard.server.common.data.kv.TsKvQuery;
  31 +import org.thingsboard.server.dao.entityview.EntityViewService;
27 32 import org.thingsboard.server.dao.exception.IncorrectParameterException;
28 33 import org.thingsboard.server.dao.service.Validator;
29 34
  35 +import java.util.ArrayList;
30 36 import java.util.Collection;
31 37 import java.util.List;
32 38
... ... @@ -44,10 +50,17 @@ public class BaseTimeseriesService implements TimeseriesService {
44 50 @Autowired
45 51 private TimeseriesDao timeseriesDao;
46 52
  53 + @Autowired
  54 + private EntityViewService entityViewService;
  55 +
47 56 @Override
48 57 public ListenableFuture<List<TsKvEntry>> findAll(EntityId entityId, List<TsKvQuery> queries) {
49 58 validate(entityId);
50 59 queries.forEach(query -> validate(query));
  60 + if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) {
  61 + EntityView entityView = entityViewService.findEntityViewById((EntityViewId) entityId);
  62 + return timeseriesDao.findAllAsync(entityView.getEntityId(), updateQueriesForEntityView(entityView, queries));
  63 + }
51 64 return timeseriesDao.findAllAsync(entityId, queries);
52 65 }
53 66
... ... @@ -56,7 +69,13 @@ public class BaseTimeseriesService implements TimeseriesService {
56 69 validate(entityId);
57 70 List<ListenableFuture<TsKvEntry>> futures = Lists.newArrayListWithExpectedSize(keys.size());
58 71 keys.forEach(key -> Validator.validateString(key, "Incorrect key " + key));
59   - keys.forEach(key -> futures.add(timeseriesDao.findLatest(entityId, key)));
  72 + if (false/*entityId.getEntityType().equals(EntityType.ENTITY_VIEW)*/) {
  73 + EntityView entityView = entityViewService.findEntityViewById((EntityViewId) entityId);
  74 + Collection<String> newKeys = chooseKeysForEntityView(entityView, keys);
  75 + newKeys.forEach(newKey -> futures.add(timeseriesDao.findLatest(entityView.getEntityId(), newKey)));
  76 + } else {
  77 + keys.forEach(key -> futures.add(timeseriesDao.findLatest(entityId, key)));
  78 + }
60 79 return Futures.allAsList(futures);
61 80 }
62 81
... ... @@ -69,6 +88,11 @@ public class BaseTimeseriesService implements TimeseriesService {
69 88 @Override
70 89 public ListenableFuture<List<Void>> save(EntityId entityId, TsKvEntry tsKvEntry) {
71 90 validate(entityId);
  91 + try {
  92 + checkForNonEntityView(entityId);
  93 + } catch (Exception e) {
  94 + e.printStackTrace();
  95 + }
72 96 if (tsKvEntry == null) {
73 97 throw new IncorrectParameterException("Key value entry can't be null");
74 98 }
... ... @@ -79,6 +103,11 @@ public class BaseTimeseriesService implements TimeseriesService {
79 103
80 104 @Override
81 105 public ListenableFuture<List<Void>> save(EntityId entityId, List<TsKvEntry> tsKvEntries, long ttl) {
  106 + try {
  107 + checkForNonEntityView(entityId);
  108 + } catch (Exception e) {
  109 + e.printStackTrace();
  110 + }
82 111 List<ListenableFuture<Void>> futures = Lists.newArrayListWithExpectedSize(tsKvEntries.size() * INSERTS_PER_ENTRY);
83 112 for (TsKvEntry tsKvEntry : tsKvEntries) {
84 113 if (tsKvEntry == null) {
... ... @@ -90,11 +119,47 @@ public class BaseTimeseriesService implements TimeseriesService {
90 119 }
91 120
92 121 private void saveAndRegisterFutures(List<ListenableFuture<Void>> futures, EntityId entityId, TsKvEntry tsKvEntry, long ttl) {
  122 + try {
  123 + checkForNonEntityView(entityId);
  124 + } catch (Exception e) {
  125 + e.printStackTrace();
  126 + }
93 127 futures.add(timeseriesDao.savePartition(entityId, tsKvEntry.getTs(), tsKvEntry.getKey(), ttl));
94 128 futures.add(timeseriesDao.saveLatest(entityId, tsKvEntry));
95 129 futures.add(timeseriesDao.save(entityId, tsKvEntry, ttl));
96 130 }
97 131
  132 + private List<TsKvQuery> updateQueriesForEntityView(EntityView entityView, List<TsKvQuery> queries) {
  133 + List<TsKvQuery> newQueries = new ArrayList<>();
  134 + entityView.getKeys().getTimeseries()
  135 + .forEach(viewKey -> queries
  136 + .forEach(query -> {
  137 + if (query.getKey().equals(viewKey)) {
  138 + if (entityView.getStartTs() == 0 && entityView.getEndTs() == 0) {
  139 + newQueries.add(updateQuery(query.getStartTs(), query.getEndTs(), viewKey, query));
  140 + } else if (entityView.getStartTs() == 0 && entityView.getEndTs() != 0) {
  141 + newQueries.add(updateQuery(query.getStartTs(), entityView.getEndTs(), viewKey, query));
  142 + } else if (entityView.getStartTs() != 0 && entityView.getEndTs() == 0) {
  143 + newQueries.add(updateQuery(entityView.getStartTs(), query.getEndTs(), viewKey, query));
  144 + } else {
  145 + newQueries.add(updateQuery(entityView.getStartTs(), entityView.getEndTs(), viewKey, query));
  146 + }
  147 + }}));
  148 + return newQueries;
  149 + }
  150 +
  151 + @Deprecated /*Will be a modified*/
  152 + private Collection<String> chooseKeysForEntityView(EntityView entityView, Collection<String> keys) {
  153 + Collection<String> newKeys = new ArrayList<>();
  154 + entityView.getKeys().getTimeseries()
  155 + .forEach(viewKey -> keys
  156 + .forEach(key -> {
  157 + if (key.equals(viewKey)) {
  158 + newKeys.add(key);
  159 + }}));
  160 + return newKeys;
  161 + }
  162 +
98 163 private static void validate(EntityId entityId) {
99 164 Validator.validateEntityId(entityId, "Incorrect entityId " + entityId);
100 165 }
... ... @@ -108,4 +173,15 @@ public class BaseTimeseriesService implements TimeseriesService {
108 173 throw new IncorrectParameterException("Incorrect TsKvQuery. Aggregation can't be empty");
109 174 }
110 175 }
  176 +
  177 + private static TsKvQuery updateQuery(Long startTs, Long endTs, String viewKey, TsKvQuery query) {
  178 + return startTs <= query.getStartTs() && endTs >= query.getEndTs() ? query :
  179 + new BaseTsKvQuery(viewKey, startTs, endTs, query.getInterval(), query.getLimit(), query.getAggregation());
  180 + }
  181 +
  182 + private static void checkForNonEntityView(EntityId entityId) throws Exception {
  183 + if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) {
  184 + throw new Exception("Entity-views were read only");
  185 + }
  186 + }
111 187 }
... ...
... ... @@ -642,6 +642,7 @@ CREATE TABLE IF NOT EXISTS thingsboard.rule_node (
642 642 CREATE TABLE IF NOT EXISTS thingsboard.entity_views (
643 643 id timeuuid,
644 644 entity_id timeuuid,
  645 + entity_type text,
645 646 tenant_id timeuuid,
646 647 customer_id timeuuid,
647 648 name text,
... ...