thingsboard-developers

Details

diff --git a/application/src/main/data/upgrade/2.1.1/schema_update.cql b/application/src/main/data/upgrade/2.1.1/schema_update.cql
index d9ba517..1329a0b 100644
--- a/application/src/main/data/upgrade/2.1.1/schema_update.cql
+++ b/application/src/main/data/upgrade/2.1.1/schema_update.cql
@@ -24,6 +24,7 @@ DROP TABLE IF EXISTS thingsboard.entity_views;
 CREATE TABLE IF NOT EXISTS thingsboard.entity_views (
     id timeuuid,
     entity_id timeuuid,
+    entity_type text,
     tenant_id timeuuid,
     customer_id timeuuid,
     name text,
@@ -33,7 +34,7 @@ CREATE TABLE IF NOT EXISTS thingsboard.entity_views (
     search_text text,
     additional_info text,
     PRIMARY KEY (id, entity_id, tenant_id, customer_id)
-    );
+);
 
 CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_name AS
     SELECT *
diff --git a/application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java b/application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java
index 600820e..7f4f23a 100644
--- a/application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java
+++ b/application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java
@@ -26,17 +26,11 @@ import org.springframework.stereotype.Component;
 import org.springframework.web.context.request.async.DeferredResult;
 import org.thingsboard.server.common.data.Customer;
 import org.thingsboard.server.common.data.Device;
+import org.thingsboard.server.common.data.EntityView;
 import org.thingsboard.server.common.data.Tenant;
 import org.thingsboard.server.common.data.asset.Asset;
 import org.thingsboard.server.common.data.exception.ThingsboardException;
-import org.thingsboard.server.common.data.id.AssetId;
-import org.thingsboard.server.common.data.id.CustomerId;
-import org.thingsboard.server.common.data.id.DeviceId;
-import org.thingsboard.server.common.data.id.EntityId;
-import org.thingsboard.server.common.data.id.EntityIdFactory;
-import org.thingsboard.server.common.data.id.RuleChainId;
-import org.thingsboard.server.common.data.id.RuleNodeId;
-import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.id.*;
 import org.thingsboard.server.common.data.rule.RuleChain;
 import org.thingsboard.server.common.data.rule.RuleNode;
 import org.thingsboard.server.controller.HttpValidationCallback;
@@ -44,6 +38,7 @@ import org.thingsboard.server.dao.alarm.AlarmService;
 import org.thingsboard.server.dao.asset.AssetService;
 import org.thingsboard.server.dao.customer.CustomerService;
 import org.thingsboard.server.dao.device.DeviceService;
+import org.thingsboard.server.dao.entityview.EntityViewService;
 import org.thingsboard.server.dao.rule.RuleChainService;
 import org.thingsboard.server.dao.tenant.TenantService;
 import org.thingsboard.server.dao.user.UserService;
@@ -66,6 +61,7 @@ public class AccessValidator {
     public static final String CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "Customer user is not allowed to perform this operation!";
     public static final String SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "System administrator is not allowed to perform this operation!";
     public static final String DEVICE_WITH_REQUESTED_ID_NOT_FOUND = "Device with requested id wasn't found!";
+    public static final String ENTITY_VIEW_WITH_REQUESTED_ID_NOT_FOUND = "Entity-view with requested id wasn't found!";
 
     @Autowired
     protected TenantService tenantService;
@@ -88,6 +84,9 @@ public class AccessValidator {
     @Autowired
     protected RuleChainService ruleChainService;
 
+    @Autowired
+    protected EntityViewService entityViewService;
+
     private ExecutorService executor;
 
     @PostConstruct
@@ -158,6 +157,9 @@ public class AccessValidator {
             case TENANT:
                 validateTenant(currentUser, entityId, callback);
                 return;
+            case ENTITY_VIEW:
+                validateEntityView(currentUser, entityId, callback);
+                return;
             default:
                 //TODO: add support of other entities
                 throw new IllegalStateException("Not Implemented!");
@@ -293,6 +295,27 @@ public class AccessValidator {
         }
     }
 
+    private void validateEntityView(final SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) {
+        if (currentUser.isSystemAdmin()) {
+            callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
+        } else {
+            ListenableFuture<EntityView> entityViewFuture = entityViewService.findEntityViewByIdAsync(new EntityViewId(entityId.getId()));
+            Futures.addCallback(entityViewFuture, getCallback(callback, entityView -> {
+                if (entityView == null) {
+                    return ValidationResult.entityNotFound(ENTITY_VIEW_WITH_REQUESTED_ID_NOT_FOUND);
+                } else {
+                    if (!entityView.getTenantId().equals(currentUser.getTenantId())) {
+                        return ValidationResult.accessDenied("Entity-view doesn't belong to the current Tenant!");
+                    } else if (currentUser.isCustomerUser() && !entityView.getCustomerId().equals(currentUser.getCustomerId())) {
+                        return ValidationResult.accessDenied("Entity-view doesn't belong to the current Customer!");
+                    } else {
+                        return ValidationResult.ok(entityView);
+                    }
+                }
+            }), executor);
+        }
+    }
+
     private <T, V> FutureCallback<T> getCallback(FutureCallback<ValidationResult> callback, Function<T, ValidationResult<V>> transformer) {
         return new FutureCallback<T>() {
             @Override
diff --git a/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java
index a9e94e9..c8a5da8 100644
--- a/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java
+++ b/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java
@@ -24,7 +24,7 @@ import java.util.Arrays;
 
 @RunWith(ClasspathSuite.class)
 @ClasspathSuite.ClassnameFilters({
-        "org.thingsboard.server.controller.sql.EntityViewControllerSqlTest",
+        "org.thingsboard.server.controller.sql.*Test",
         })
 public class ControllerSqlTestSuite {
 
diff --git a/application/src/test/java/org/thingsboard/server/controller/nosql/EntityViewControllerNoSqlTest.java b/application/src/test/java/org/thingsboard/server/controller/nosql/EntityViewControllerNoSqlTest.java
index ad066fc..404e4e2 100644
--- a/application/src/test/java/org/thingsboard/server/controller/nosql/EntityViewControllerNoSqlTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/nosql/EntityViewControllerNoSqlTest.java
@@ -16,9 +16,11 @@
 package org.thingsboard.server.controller.nosql;
 
 import org.thingsboard.server.controller.BaseEntityViewControllerTest;
+import org.thingsboard.server.dao.service.DaoNoSqlTest;
 
 /**
  * Created by Victor Basanets on 8/27/2017.
  */
+@DaoNoSqlTest
 public class EntityViewControllerNoSqlTest extends BaseEntityViewControllerTest {
 }
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 813a9ac..49dd209 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
@@ -39,8 +39,8 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo<EntityViewId>
     private CustomerId customerId;
     private String name;
     private TelemetryEntityView keys;
-    private Long tsBegin;
-    private Long tsEnd;
+    private long startTs;
+    private long endTs;
 
     public EntityView() {
         super();
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/objects/AttributesEntityView.java b/common/data/src/main/java/org/thingsboard/server/common/data/objects/AttributesEntityView.java
index b1d270c..1c32579 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/objects/AttributesEntityView.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/objects/AttributesEntityView.java
@@ -44,9 +44,4 @@ public class AttributesEntityView {
     public AttributesEntityView(AttributesEntityView obj) {
         this(obj.getCs(), obj.getSs(), obj.getSh());
     }
-
-    @Override
-    public String toString() {
-        return "{cs=" + cs + ", ss=" + ss + ", sh=" + sh + '}';
-    }
 }
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/objects/TelemetryEntityView.java b/common/data/src/main/java/org/thingsboard/server/common/data/objects/TelemetryEntityView.java
index e7398e6..c899c65 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/objects/TelemetryEntityView.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/objects/TelemetryEntityView.java
@@ -40,9 +40,4 @@ public class TelemetryEntityView {
     public TelemetryEntityView(TelemetryEntityView obj) {
         this(obj.getTimeseries(), obj.getAttributes());
     }
-
-    @Override
-    public String toString() {
-        return "{timeseries=" + timeseries + ", attributes=" + attributes + '}';
-    }
 }
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
new file mode 100644
index 0000000..5716460
--- /dev/null
+++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java
@@ -0,0 +1,108 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.dao.entityview;
+
+import com.datastax.driver.core.Statement;
+import com.datastax.driver.core.querybuilder.Select;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.thingsboard.server.common.data.EntitySubtype;
+import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.EntityView;
+import org.thingsboard.server.common.data.page.TextPageLink;
+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.util.NoSqlDao;
+
+import java.util.*;
+
+import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
+import static org.thingsboard.server.dao.model.ModelConstants.*;
+
+/**
+ * Created by Victor Basanets on 9/06/2017.
+ */
+@Component
+@Slf4j
+@NoSqlDao
+public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<EntityViewEntity, EntityView> implements EntityViewDao {
+
+    @Override
+    protected Class<EntityViewEntity> getColumnFamilyClass() {
+        return EntityViewEntity.class;
+    }
+
+    @Override
+    protected String getColumnFamilyName() {
+        return ENTITY_VIEW_TABLE_FAMILY_NAME;
+    }
+
+    @Override
+    public EntityView save(EntityView domain) {
+        EntityView savedEntityView = super.save(domain);
+        EntitySubtype entitySubtype = new EntitySubtype(savedEntityView.getTenantId(), EntityType.ENTITY_VIEW,
+                savedEntityView.getId().getEntityType().toString());
+        EntitySubtypeEntity entitySubtypeEntity = new EntitySubtypeEntity(entitySubtype);
+        Statement saveStatement = cluster.getMapper(EntitySubtypeEntity.class).saveQuery(entitySubtypeEntity);
+        executeWrite(saveStatement);
+        return savedEntityView;
+    }
+
+    @Override
+    public List<EntityView> findEntityViewByTenantId(UUID tenantId, TextPageLink pageLink) {
+        log.debug("Try to find entity-views by tenantId [{}] and pageLink [{}]", tenantId, pageLink);
+        List<EntityViewEntity> entityViewEntities =
+                findPageWithTextSearch(ENTITY_VIEW_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
+                Collections.singletonList(eq(ENTITY_VIEW_TENANT_ID_PROPERTY, tenantId)), pageLink);
+
+        log.trace("Found entity-views [{}] by tenantId [{}] and pageLink [{}]", entityViewEntities, tenantId, pageLink);
+        return DaoUtil.convertDataList(entityViewEntities);
+    }
+
+    @Override
+    public Optional<EntityView> findEntityViewByTenantIdAndName(UUID tenantId, String entityViewName) {
+        return Optional.ofNullable(DaoUtil.getData(
+                findOneByStatement(select().from(ENTITY_VIEW_TENANT_AND_NAME_VIEW_NAME).where()
+                        .and(eq(ENTITY_VIEW_TENANT_ID_PROPERTY, tenantId))
+                        .and(eq(ENTITY_VIEW_NAME_PROPERTY, entityViewName))))
+        );
+    }
+
+    @Override
+    public List<EntityView> findEntityViewByTenantIdAndEntityId(UUID tenantId, UUID entityId, TextPageLink pageLink) {
+        log.debug("Try to find entity-views by tenantId [{}], entityId[{}] and pageLink [{}]", tenantId, entityId, pageLink);
+        List<EntityViewEntity> entityViewEntities = findPageWithTextSearch(DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
+                Arrays.asList(eq(DEVICE_CUSTOMER_ID_PROPERTY, entityId),
+                        eq(DEVICE_TENANT_ID_PROPERTY, tenantId)),
+                pageLink);
+
+        log.trace("Found entity-views [{}] by tenantId [{}], entityId [{}] and pageLink [{}]", entityViewEntities, tenantId, entityId, pageLink);
+        return DaoUtil.convertDataList(entityViewEntities);
+    }
+
+    @Override
+    public List<EntityView> findEntityViewsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) {
+        return null;
+    }
+
+    @Override
+    public List<EntityView> findEntityViewsByTenantIdAndCustomerIdAndEntityId(UUID tenantId, UUID customerId, UUID entityId, TextPageLink pageLink) {
+        return null;
+    }
+}
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 25404db..5cbbef8 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
@@ -30,6 +30,14 @@ import java.util.UUID;
 public interface EntityViewDao extends Dao<EntityView> {
 
     /**
+     * Save or update device object
+     *
+     * @param entityView the entity-view object
+     * @return saved entity-view object
+     */
+    EntityView save(EntityView entityView);
+
+    /**
      * Find entity views by tenantId and page link.
      *
      * @param tenantId the tenantId
diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java
index 943d35e..6de86be 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java
@@ -15,12 +15,10 @@
  */
 package org.thingsboard.server.dao.entityview;
 
+import com.google.common.util.concurrent.ListenableFuture;
 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.EntityId;
-import org.thingsboard.server.common.data.id.EntityViewId;
-import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.id.*;
 import org.thingsboard.server.common.data.page.TextPageData;
 import org.thingsboard.server.common.data.page.TextPageLink;
 
@@ -57,4 +55,6 @@ public interface EntityViewService {
                                                                                TextPageLink pageLink);
 
     void unassignCustomerEntityViews(TenantId tenantId, CustomerId customerId);
+
+    ListenableFuture<EntityView> findEntityViewByIdAsync(EntityViewId entityViewId);
 }
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 6554083..31d3b30 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
@@ -15,11 +15,14 @@
  */
 package org.thingsboard.server.dao.entityview;
 
+import com.google.common.util.concurrent.ListenableFuture;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cache.Cache;
 import org.springframework.cache.CacheManager;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Service;
 import org.thingsboard.server.common.data.Customer;
 import org.thingsboard.server.common.data.EntityView;
@@ -40,6 +43,8 @@ import org.thingsboard.server.dao.tenant.TenantDao;
 import java.util.ArrayList;
 import java.util.List;
 
+import static org.thingsboard.server.common.data.CacheConstants.DEVICE_CACHE;
+import static org.thingsboard.server.common.data.CacheConstants.ENTITY_VIEW_CACHE;
 import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
 import static org.thingsboard.server.dao.service.Validator.validateId;
 import static org.thingsboard.server.dao.service.Validator.validatePageLink;
@@ -67,6 +72,10 @@ public class EntityViewServiceImpl extends AbstractEntityService
     @Autowired
     private CustomerDao customerDao;
 
+    @Autowired
+    private CacheManager cacheManager;
+
+    @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}")
     @Override
     public EntityView findEntityViewById(EntityViewId entityViewId) {
         log.trace("Executing findEntityViewById [{}]", entityViewId);
@@ -82,6 +91,7 @@ public class EntityViewServiceImpl extends AbstractEntityService
                 .orElse(null);
     }
 
+    @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityView.id}")
     @Override
     public EntityView saveEntityView(EntityView entityView) {
         log.trace("Executing save entity view [{}]", entityView);
@@ -106,12 +116,14 @@ public class EntityViewServiceImpl extends AbstractEntityService
     @Override
     public void deleteEntityView(EntityViewId entityViewId) {
         log.trace("Executing deleteEntityView [{}]", entityViewId);
+        Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE);
         validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId);
         deleteEntityRelations(entityViewId);
         EntityView entityView = entityViewDao.findById(entityViewId.getId());
         List<Object> list = new ArrayList<>();
         list.add(entityView.getTenantId());
         list.add(entityView.getName());
+        cache.evict(list);
         entityViewDao.removeById(entityViewId.getId());
     }
 
@@ -124,6 +136,7 @@ public class EntityViewServiceImpl extends AbstractEntityService
         return new TextPageData<>(entityViews, pageLink);
     }
 
+    @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #entityId, #pageLink}")
     @Override
     public TextPageData<EntityView> findEntityViewByTenantIdAndEntityId(TenantId tenantId, EntityId entityId,
                                                                     TextPageLink pageLink) {
@@ -163,6 +176,7 @@ public class EntityViewServiceImpl extends AbstractEntityService
         return new TextPageData<>(entityViews, pageLink);
     }
 
+    @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #customerId, #entityId, #pageLink}")
     @Override
     public TextPageData<EntityView> findEntityViewsByTenantIdAndCustomerIdAndEntityId(TenantId tenantId,
                                                                                       CustomerId customerId,
@@ -190,6 +204,13 @@ public class EntityViewServiceImpl extends AbstractEntityService
         new CustomerEntityViewsUnAssigner(tenantId).removeEntities(customerId);
     }
 
+    @Override
+    public ListenableFuture<EntityView> findEntityViewByIdAsync(EntityViewId entityViewId) {
+        log.trace("Executing findEntityViewById [{}]", entityViewId);
+        validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId);
+        return entityViewDao.findByIdAsync(entityViewId.getId());
+    }
+
     private DataValidator<EntityView> entityViewValidator =
             new DataValidator<EntityView>() {
 
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 d06ddbd..6932bea 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
@@ -136,7 +136,6 @@ public class ModelConstants {
     public static final String DEVICE_NAME_PROPERTY = "name";
     public static final String DEVICE_TYPE_PROPERTY = "type";
     public static final String DEVICE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
-
     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";
@@ -152,11 +151,12 @@ 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_TYPE_PROPERTY = "type_entity";
+    public static final String ENTITY_VIEW_TENANT_AND_NAME_VIEW_NAME = "entity_view_by_tenant_and_name";
     public static final String ENTITY_VIEW_KEYS_PROPERTY = "keys";
     public static final String ENTITY_VIEW_TS_BEGIN_PROPERTY = "ts_begin";
     public static final String ENTITY_VIEW_TS_END_PROPERTY = "ts_end";
     public static final String ENTITY_VIEW_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
+    public static final String ENTITY_VIEW_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "entity_view_by_tenant_and_search_text";
 
     /**
      * Cassandra audit log constants.
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 65914dd..990ff70 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
@@ -19,24 +19,26 @@ import com.datastax.driver.core.utils.UUIDs;
 import com.datastax.driver.mapping.annotations.PartitionKey;
 import com.datastax.driver.mapping.annotations.Table;
 import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.ToString;
 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.DeviceId;
-import org.thingsboard.server.common.data.id.EntityViewId;
-import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.id.*;
 import org.thingsboard.server.common.data.objects.TelemetryEntityView;
 import org.thingsboard.server.dao.model.ModelConstants;
 import org.thingsboard.server.dao.model.SearchTextEntity;
 
 import javax.persistence.Column;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
 
 import java.io.IOException;
 import java.util.UUID;
 
+import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_TYPE_PROPERTY;
 import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_TABLE_FAMILY_NAME;
 import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY;
 
@@ -57,6 +59,10 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
     @Column(name = ModelConstants.ENTITY_VIEW_ENTITY_ID_PROPERTY)
     private UUID entityId;
 
+    @Enumerated(EnumType.STRING)
+    @Column(name = ENTITY_TYPE_PROPERTY)
+    private EntityType entityType;
+
     @PartitionKey(value = 2)
     @Column(name = ModelConstants.ENTITY_VIEW_TENANT_ID_PROPERTY)
     private UUID tenantId;
@@ -68,9 +74,8 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
     @Column(name = ModelConstants.ENTITY_VIEW_NAME_PROPERTY)
     private String name;
 
-    @Type(type = "json")
     @Column(name = ModelConstants.ENTITY_VIEW_KEYS_PROPERTY)
-    private JsonNode keys;
+    private String keys;
 
     @Column(name = ModelConstants.ENTITY_VIEW_TS_BEGIN_PROPERTY)
     private String tsBegin;
@@ -85,6 +90,8 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
     @Column(name = ModelConstants.ENTITY_VIEW_ADDITIONAL_INFO_PROPERTY)
     private JsonNode additionalInfo;
 
+    private static final ObjectMapper mapper = new ObjectMapper();
+
     public EntityViewEntity() {
         super();
     }
@@ -95,6 +102,7 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
         }
         if (entityView.getEntityId() != null) {
             this.entityId = entityView.getEntityId().getId();
+            this.entityType = entityView.getEntityId().getEntityType();
         }
         if (entityView.getTenantId() != null) {
             this.tenantId = entityView.getTenantId().getId();
@@ -103,13 +111,13 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
             this.customerId = entityView.getCustomerId().getId();
         }
         this.name = entityView.getName();
-//        try {
-//            this.keys = entityView.getKeys();
-//        } catch (IOException e) {
-//            e.printStackTrace();
-//        }
-        this.tsBegin = entityView.getTsBegin() != null ? String.valueOf(entityView.getTsBegin()) : "0";
-        this.tsEnd = entityView.getTsEnd() != null ? String.valueOf(entityView.getTsEnd()) : "0";
+        try {
+            this.keys = mapper.writeValueAsString(entityView.getKeys());
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        this.tsBegin = entityView.getStartTs() != 0L ? String.valueOf(entityView.getStartTs()) : "0";
+        this.tsEnd = entityView.getEndTs() != 0L ? String.valueOf(entityView.getEndTs()) : "0";
         this.searchText = entityView.getSearchText();
         this.additionalInfo = entityView.getAdditionalInfo();
     }
@@ -124,7 +132,7 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
         EntityView entityView = new EntityView(new EntityViewId(id));
         entityView.setCreatedTime(UUIDs.unixTimestamp(id));
         if (entityId != null) {
-            entityView.setEntityId(new DeviceId(entityId));
+            entityView.setEntityId(EntityIdFactory.getByTypeAndId(entityType.name(), entityId.toString()));
         }
         if (tenantId != null) {
             entityView.setTenantId(new TenantId(tenantId));
@@ -133,13 +141,13 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
             entityView.setCustomerId(new CustomerId(customerId));
         }
         entityView.setName(name);
-//        try {
-//            entityView.setKeys((TelemetryEntityView) entityView.getKeys().toObject(keys));
-//        } catch (IOException e) {
-//            e.printStackTrace();
-//        }
-        entityView.setTsBegin(Long.parseLong(tsBegin));
-        entityView.setTsEnd(Long.parseLong(tsEnd));
+        try {
+            entityView.setKeys(mapper.readValue(keys, TelemetryEntityView.class));
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        entityView.setStartTs(Long.parseLong(tsBegin));
+        entityView.setEndTs(Long.parseLong(tsEnd));
         entityView.setAdditionalInfo(additionalInfo);
         return entityView;
     }
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 9136717..a89d3de 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
@@ -34,7 +34,6 @@ import org.thingsboard.server.dao.util.mapping.JsonStringType;
 import javax.persistence.*;
 import java.io.IOException;
 
-import static org.thingsboard.server.dao.model.ModelConstants.AUDIT_LOG_ENTITY_TYPE_PROPERTY;
 import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_TYPE_PROPERTY;
 
 /**
@@ -106,8 +105,8 @@ public class EntityViewEntity extends BaseSqlEntity<EntityView> implements Searc
         } catch (IOException e) {
             e.printStackTrace();
         }
-        this.tsBegin = entityView.getTsBegin() != null ? String.valueOf(entityView.getTsBegin()) : "0";
-        this.tsEnd = entityView.getTsEnd() != null ? String.valueOf(entityView.getTsEnd()) : "0";
+        this.tsBegin = entityView.getStartTs() != 0L ? String.valueOf(entityView.getStartTs()) : "0";
+        this.tsEnd = entityView.getEndTs() != 0L ? String.valueOf(entityView.getEndTs()) : "0";
         this.searchText = entityView.getSearchText();
         this.additionalInfo = entityView.getAdditionalInfo();
     }
@@ -142,8 +141,8 @@ public class EntityViewEntity extends BaseSqlEntity<EntityView> implements Searc
         } catch (IOException e) {
             e.printStackTrace();
         }
-        entityView.setTsBegin(Long.parseLong(tsBegin));
-        entityView.setTsEnd(Long.parseLong(tsEnd));
+        entityView.setStartTs(Long.parseLong(tsBegin));
+        entityView.setEndTs(Long.parseLong(tsEnd));
         entityView.setAdditionalInfo(additionalInfo);
         return entityView;
     }
diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java
index c981378..9b837b2 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java
@@ -21,12 +21,18 @@ import com.google.common.util.concurrent.ListenableFuture;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.EntityView;
 import org.thingsboard.server.common.data.id.EntityId;
+import org.thingsboard.server.common.data.id.EntityViewId;
+import org.thingsboard.server.common.data.kv.BaseTsKvQuery;
 import org.thingsboard.server.common.data.kv.TsKvEntry;
 import org.thingsboard.server.common.data.kv.TsKvQuery;
+import org.thingsboard.server.dao.entityview.EntityViewService;
 import org.thingsboard.server.dao.exception.IncorrectParameterException;
 import org.thingsboard.server.dao.service.Validator;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 
@@ -44,10 +50,17 @@ public class BaseTimeseriesService implements TimeseriesService {
     @Autowired
     private TimeseriesDao timeseriesDao;
 
+    @Autowired
+    private EntityViewService entityViewService;
+
     @Override
     public ListenableFuture<List<TsKvEntry>> findAll(EntityId entityId, List<TsKvQuery> queries) {
         validate(entityId);
         queries.forEach(query -> validate(query));
+        if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) {
+            EntityView entityView = entityViewService.findEntityViewById((EntityViewId) entityId);
+            return timeseriesDao.findAllAsync(entityView.getEntityId(), updateQueriesForEntityView(entityView, queries));
+        }
         return timeseriesDao.findAllAsync(entityId, queries);
     }
 
@@ -56,7 +69,13 @@ public class BaseTimeseriesService implements TimeseriesService {
         validate(entityId);
         List<ListenableFuture<TsKvEntry>> futures = Lists.newArrayListWithExpectedSize(keys.size());
         keys.forEach(key -> Validator.validateString(key, "Incorrect key " + key));
-        keys.forEach(key -> futures.add(timeseriesDao.findLatest(entityId, key)));
+        if (false/*entityId.getEntityType().equals(EntityType.ENTITY_VIEW)*/) {
+            EntityView entityView = entityViewService.findEntityViewById((EntityViewId) entityId);
+            Collection<String> newKeys = chooseKeysForEntityView(entityView, keys);
+            newKeys.forEach(newKey -> futures.add(timeseriesDao.findLatest(entityView.getEntityId(), newKey)));
+        } else {
+            keys.forEach(key -> futures.add(timeseriesDao.findLatest(entityId, key)));
+        }
         return Futures.allAsList(futures);
     }
 
@@ -69,6 +88,11 @@ public class BaseTimeseriesService implements TimeseriesService {
     @Override
     public ListenableFuture<List<Void>> save(EntityId entityId, TsKvEntry tsKvEntry) {
         validate(entityId);
+        try {
+            checkForNonEntityView(entityId);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
         if (tsKvEntry == null) {
             throw new IncorrectParameterException("Key value entry can't be null");
         }
@@ -79,6 +103,11 @@ public class BaseTimeseriesService implements TimeseriesService {
 
     @Override
     public ListenableFuture<List<Void>> save(EntityId entityId, List<TsKvEntry> tsKvEntries, long ttl) {
+        try {
+            checkForNonEntityView(entityId);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
         List<ListenableFuture<Void>> futures = Lists.newArrayListWithExpectedSize(tsKvEntries.size() * INSERTS_PER_ENTRY);
         for (TsKvEntry tsKvEntry : tsKvEntries) {
             if (tsKvEntry == null) {
@@ -90,11 +119,47 @@ public class BaseTimeseriesService implements TimeseriesService {
     }
 
     private void saveAndRegisterFutures(List<ListenableFuture<Void>> futures, EntityId entityId, TsKvEntry tsKvEntry, long ttl) {
+        try {
+            checkForNonEntityView(entityId);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
         futures.add(timeseriesDao.savePartition(entityId, tsKvEntry.getTs(), tsKvEntry.getKey(), ttl));
         futures.add(timeseriesDao.saveLatest(entityId, tsKvEntry));
         futures.add(timeseriesDao.save(entityId, tsKvEntry, ttl));
     }
 
+    private List<TsKvQuery> updateQueriesForEntityView(EntityView entityView, List<TsKvQuery> queries) {
+        List<TsKvQuery> newQueries = new ArrayList<>();
+        entityView.getKeys().getTimeseries()
+                .forEach(viewKey -> queries
+                        .forEach(query -> {
+                            if (query.getKey().equals(viewKey)) {
+                                if (entityView.getStartTs() == 0 && entityView.getEndTs() == 0) {
+                                    newQueries.add(updateQuery(query.getStartTs(), query.getEndTs(), viewKey, query));
+                                } else if (entityView.getStartTs() == 0 && entityView.getEndTs() != 0) {
+                                    newQueries.add(updateQuery(query.getStartTs(), entityView.getEndTs(), viewKey, query));
+                                } else if (entityView.getStartTs() != 0 && entityView.getEndTs() == 0) {
+                                    newQueries.add(updateQuery(entityView.getStartTs(), query.getEndTs(), viewKey, query));
+                                } else {
+                                    newQueries.add(updateQuery(entityView.getStartTs(), entityView.getEndTs(), viewKey, query));
+                                }
+                            }}));
+        return newQueries;
+    }
+
+    @Deprecated /*Will be a modified*/
+    private Collection<String> chooseKeysForEntityView(EntityView entityView, Collection<String> keys) {
+        Collection<String> newKeys = new ArrayList<>();
+        entityView.getKeys().getTimeseries()
+                .forEach(viewKey -> keys
+                        .forEach(key -> {
+                            if (key.equals(viewKey)) {
+                                newKeys.add(key);
+                            }}));
+        return newKeys;
+    }
+
     private static void validate(EntityId entityId) {
         Validator.validateEntityId(entityId, "Incorrect entityId " + entityId);
     }
@@ -108,4 +173,15 @@ public class BaseTimeseriesService implements TimeseriesService {
             throw new IncorrectParameterException("Incorrect TsKvQuery. Aggregation can't be empty");
         }
     }
+
+    private static TsKvQuery updateQuery(Long startTs, Long endTs, String viewKey, TsKvQuery query) {
+        return startTs <= query.getStartTs() && endTs >= query.getEndTs() ? query :
+                new BaseTsKvQuery(viewKey, startTs, endTs, query.getInterval(), query.getLimit(), query.getAggregation());
+    }
+
+    private static void checkForNonEntityView(EntityId entityId) throws Exception {
+        if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) {
+            throw new Exception("Entity-views were read only");
+        }
+    }
 }
diff --git a/dao/src/main/resources/cassandra/schema.cql b/dao/src/main/resources/cassandra/schema.cql
index bdd413d..68f196f 100644
--- a/dao/src/main/resources/cassandra/schema.cql
+++ b/dao/src/main/resources/cassandra/schema.cql
@@ -642,6 +642,7 @@ CREATE TABLE IF NOT EXISTS  thingsboard.rule_node (
 CREATE TABLE IF NOT EXISTS thingsboard.entity_views (
     id timeuuid,
     entity_id timeuuid,
+    entity_type text,
     tenant_id timeuuid,
     customer_id timeuuid,
     name text,