From b7ed7ea039e96e65218eba375a14d36d2091e7f0 Mon Sep 17 00:00:00 2001 From: hagaic Date: Tue, 21 Aug 2018 00:58:45 +0300 Subject: [PATCH 001/118] hybrid db initial commit --- .../install/ThingsboardInstallService.java | 2 +- .../CassandraDatabaseSchemaService.java | 4 ++-- .../CassandraDatabaseUpgradeService.java | 4 ++-- .../src/main/resources/thingsboard.yml | 7 +++++- .../dao/cassandra/CassandraCluster.java | 4 ++-- .../cassandra/CassandraInstallCluster.java | 4 ++-- .../dao/cassandra/CassandraQueryOptions.java | 4 ++-- .../dao/cassandra/CassandraSocketOptions.java | 4 ++-- .../dao/sql/timeseries/JpaTimeseriesDao.java | 3 ++- .../CassandraBaseTimeseriesDao.java | 3 ++- .../server/dao/util/BufferedRateLimiter.java | 2 +- .../server/dao/util/NoSqlAnyDao.java | 22 +++++++++++++++++++ .../server/dao/util/NoSqlTsDao.java | 22 +++++++++++++++++++ .../thingsboard/server/dao/util/SqlTsDao.java | 22 +++++++++++++++++++ 14 files changed, 90 insertions(+), 17 deletions(-) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/NoSqlAnyDao.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/NoSqlTsDao.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/SqlTsDao.java diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index f863d0bb2a..d0add1aa89 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -116,7 +116,7 @@ public class ThingsboardInstallService { log.info("Installing DataBase schema..."); - databaseSchemaService.createDatabaseSchema(); + databaseSchemaService.createDatabaseSchema();//TODO log.info("Loading system data..."); diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseSchemaService.java index dd76b21844..6eeeb0a620 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseSchemaService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseSchemaService.java @@ -20,7 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; import org.thingsboard.server.dao.cassandra.CassandraInstallCluster; -import org.thingsboard.server.dao.util.NoSqlDao; +import org.thingsboard.server.dao.util.NoSqlAnyDao; import org.thingsboard.server.service.install.cql.CQLStatementsParser; import java.nio.file.Path; @@ -28,7 +28,7 @@ import java.nio.file.Paths; import java.util.List; @Service -@NoSqlDao +@NoSqlAnyDao @Profile("install") @Slf4j public class CassandraDatabaseSchemaService implements DatabaseSchemaService { 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 f4ff92cf23..2cbd167242 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 @@ -23,7 +23,7 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.dao.cassandra.CassandraCluster; import org.thingsboard.server.dao.cassandra.CassandraInstallCluster; import org.thingsboard.server.dao.dashboard.DashboardService; -import org.thingsboard.server.dao.util.NoSqlDao; +import org.thingsboard.server.dao.util.NoSqlAnyDao; import org.thingsboard.server.service.install.cql.CQLStatementsParser; import org.thingsboard.server.service.install.cql.CassandraDbHelper; @@ -45,7 +45,7 @@ import static org.thingsboard.server.service.install.DatabaseHelper.TENANT_ID; import static org.thingsboard.server.service.install.DatabaseHelper.TITLE; @Service -@NoSqlDao +@NoSqlAnyDao @Profile("install") @Slf4j public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService { diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 743a8607b5..5573c7538b 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -151,6 +151,7 @@ quota: # Enable Host API Limits enabled: "${QUOTA_TENANT_ENABLED:false}" # Array of whitelist tenants + # Array of whitelist tenants whitelist: "${QUOTA_TENANT_WHITELIST:}" # Array of blacklist tenants blacklist: "${QUOTA_HOST_BLACKLIST:}" @@ -160,6 +161,10 @@ quota: database: type: "${DATABASE_TYPE:sql}" # cassandra OR sql + entities: + type: "${DATABASE_TYPE:sql}" # cassandra OR sql + ts: + type: "${DATABASE_TYPE:cassandra}" # cassandra OR sql # Cassandra driver configuration parameters cassandra: @@ -206,7 +211,7 @@ cassandra: write_consistency_level: "${CASSANDRA_WRITE_CONSISTENCY_LEVEL:ONE}" default_fetch_size: "${CASSANDRA_DEFAULT_FETCH_SIZE:2000}" # Specify partitioning size for timestamp key-value storage. Example MINUTES, HOURS, DAYS, MONTHS,INDEFINITE - ts_key_value_partitioning: "${TS_KV_PARTITIONING:MONTHS}" + ts_key_value_partitioning: "${TS_KV_PARTITIONING:INDEFINITE}" ts_key_value_ttl: "${TS_KV_TTL:0}" buffer_size: "${CASSANDRA_QUERY_BUFFER_SIZE:200000}" concurrent_limit: "${CASSANDRA_QUERY_CONCURRENT_LIMIT:1000}" diff --git a/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraCluster.java b/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraCluster.java index 567523228a..19409ad146 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraCluster.java +++ b/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraCluster.java @@ -17,12 +17,12 @@ package org.thingsboard.server.dao.cassandra; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; -import org.thingsboard.server.dao.util.NoSqlDao; +import org.thingsboard.server.dao.util.NoSqlAnyDao; import javax.annotation.PostConstruct; @Component -@NoSqlDao +@NoSqlAnyDao public class CassandraCluster extends AbstractCassandraCluster { @Value("${cassandra.keyspace_name}") diff --git a/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraInstallCluster.java b/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraInstallCluster.java index 02968078f1..247a204ee5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraInstallCluster.java +++ b/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraInstallCluster.java @@ -17,12 +17,12 @@ package org.thingsboard.server.dao.cassandra; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; -import org.thingsboard.server.dao.util.NoSqlDao; +import org.thingsboard.server.dao.util.NoSqlAnyDao; import javax.annotation.PostConstruct; @Component -@NoSqlDao +@NoSqlAnyDao @Profile("install") public class CassandraInstallCluster extends AbstractCassandraCluster { diff --git a/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraQueryOptions.java b/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraQueryOptions.java index 474cad7c6a..1f09342ca1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraQueryOptions.java +++ b/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraQueryOptions.java @@ -21,14 +21,14 @@ import lombok.Data; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; -import org.thingsboard.server.dao.util.NoSqlDao; +import org.thingsboard.server.dao.util.NoSqlAnyDao; import javax.annotation.PostConstruct; @Component @Configuration @Data -@NoSqlDao +@NoSqlAnyDao public class CassandraQueryOptions { @Value("${cassandra.query.default_fetch_size}") diff --git a/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraSocketOptions.java b/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraSocketOptions.java index 8171ccc07f..15263c8b34 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraSocketOptions.java +++ b/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraSocketOptions.java @@ -20,14 +20,14 @@ import lombok.Data; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; -import org.thingsboard.server.dao.util.NoSqlDao; +import org.thingsboard.server.dao.util.NoSqlAnyDao; import javax.annotation.PostConstruct; @Component @Configuration @Data -@NoSqlDao +@NoSqlAnyDao public class CassandraSocketOptions { @Value("${cassandra.socket.connect_timeout}") diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/timeseries/JpaTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/timeseries/JpaTimeseriesDao.java index e5f145f0fd..df72943249 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/timeseries/JpaTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/timeseries/JpaTimeseriesDao.java @@ -42,6 +42,7 @@ import org.thingsboard.server.dao.sql.JpaAbstractDaoListeningExecutorService; import org.thingsboard.server.dao.timeseries.TimeseriesDao; import org.thingsboard.server.dao.timeseries.TsInsertExecutorType; import org.thingsboard.server.dao.util.SqlDao; +import org.thingsboard.server.dao.util.SqlTsDao; import javax.annotation.Nullable; import javax.annotation.PostConstruct; @@ -58,7 +59,7 @@ import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUID; @Component @Slf4j -@SqlDao +@SqlTsDao public class JpaTimeseriesDao extends JpaAbstractDaoListeningExecutorService implements TimeseriesDao { @Value("${sql.ts_inserts_executor_type}") diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java index c025e64a31..be36d3b156 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java @@ -47,6 +47,7 @@ import org.thingsboard.server.common.data.kv.TsKvQuery; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.nosql.CassandraAbstractAsyncDao; import org.thingsboard.server.dao.util.NoSqlDao; +import org.thingsboard.server.dao.util.NoSqlTsDao; import javax.annotation.Nullable; import javax.annotation.PostConstruct; @@ -68,7 +69,7 @@ import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; */ @Component @Slf4j -@NoSqlDao +@NoSqlTsDao public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implements TimeseriesDao { private static final int MIN_AGGREGATION_STEP_MS = 1000; diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/BufferedRateLimiter.java b/dao/src/main/java/org/thingsboard/server/dao/util/BufferedRateLimiter.java index 817845b54a..eab05b2fdb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/BufferedRateLimiter.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/BufferedRateLimiter.java @@ -34,7 +34,7 @@ import java.util.concurrent.atomic.AtomicInteger; @Component @Slf4j -@NoSqlDao +@NoSqlAnyDao public class BufferedRateLimiter implements AsyncRateLimiter { private final ListeningExecutorService pool = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/NoSqlAnyDao.java b/dao/src/main/java/org/thingsboard/server/dao/util/NoSqlAnyDao.java new file mode 100644 index 0000000000..7e7aefa3c3 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/util/NoSqlAnyDao.java @@ -0,0 +1,22 @@ +/** + * 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.util; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; + +@ConditionalOnExpression("'${database.type}'=='cassandra' || '${database.ts.type}'=='cassandra'") +public @interface NoSqlAnyDao { +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/NoSqlTsDao.java b/dao/src/main/java/org/thingsboard/server/dao/util/NoSqlTsDao.java new file mode 100644 index 0000000000..748365fe41 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/util/NoSqlTsDao.java @@ -0,0 +1,22 @@ +/** + * 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.util; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; + +@ConditionalOnProperty(prefix = "database.ts", value = "type", havingValue = "cassandra") +public @interface NoSqlTsDao { +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/SqlTsDao.java b/dao/src/main/java/org/thingsboard/server/dao/util/SqlTsDao.java new file mode 100644 index 0000000000..0470486408 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/util/SqlTsDao.java @@ -0,0 +1,22 @@ +/** + * 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.util; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; + +@ConditionalOnProperty(prefix = "database.ts", value = "type", havingValue = "sql") +public @interface SqlTsDao { +} From c9fc57b3fd88137ac48c2fa9d47cf12a7703993a Mon Sep 17 00:00:00 2001 From: hagaic Date: Tue, 21 Aug 2018 02:05:45 +0300 Subject: [PATCH 002/118] make hybrid db optional --- .../thingsboard/server/install/ThingsboardInstallService.java | 2 +- application/src/main/resources/thingsboard.yml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index d0add1aa89..884afc06c9 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -116,7 +116,7 @@ public class ThingsboardInstallService { log.info("Installing DataBase schema..."); - databaseSchemaService.createDatabaseSchema();//TODO + databaseSchemaService.createDatabaseSchema();//TODO issue 1005 - create both SQL and C* schemas in hybrid mode log.info("Loading system data..."); diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 5573c7538b..a379e472aa 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -164,7 +164,8 @@ database: entities: type: "${DATABASE_TYPE:sql}" # cassandra OR sql ts: - type: "${DATABASE_TYPE:cassandra}" # cassandra OR sql + type: "${DATABASE_TYPE:sql}" # cassandra OR sql (for hybrid mode, only this value should be cassandra) + # Cassandra driver configuration parameters cassandra: From 4976a5326f5953a11a8edb80261aa21ffc9add10 Mon Sep 17 00:00:00 2001 From: hagaic Date: Wed, 22 Aug 2018 04:14:19 +0300 Subject: [PATCH 003/118] install hybrid db schema --- .../install/ThingsboardInstallService.java | 2 +- ...assandraAbstractDatabaseSchemaService.java | 56 ++ .../CassandraDatabaseSchemaService.java | 28 +- .../CassandraEntityDatabaseSchemaService.java | 25 + .../CassandraTsDatabaseSchemaService.java | 25 + .../install/HybridDatabaseSchemaService.java | 44 ++ .../SqlAbstractDatabaseSchemaService.java | 65 ++ .../install/SqlDatabaseSchemaService.java | 34 +- .../SqlEntityDatabaseSchemaService.java | 25 + .../install/SqlTsDatabaseSchemaService.java | 25 + .../server/dao/util/HybridDao.java | 22 + .../resources/cassandra/schema-entities.cql | 605 ++++++++++++++++++ .../main/resources/cassandra/schema-ts.cql | 55 ++ .../main/resources/sql/schema-entities.sql | 229 +++++++ dao/src/main/resources/sql/schema-ts.sql | 39 ++ 15 files changed, 1229 insertions(+), 50 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/install/CassandraAbstractDatabaseSchemaService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/install/CassandraEntityDatabaseSchemaService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseSchemaService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/install/HybridDatabaseSchemaService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/install/SqlAbstractDatabaseSchemaService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/install/SqlEntityDatabaseSchemaService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/install/SqlTsDatabaseSchemaService.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/HybridDao.java create mode 100644 dao/src/main/resources/cassandra/schema-entities.cql create mode 100644 dao/src/main/resources/cassandra/schema-ts.cql create mode 100644 dao/src/main/resources/sql/schema-entities.sql create mode 100644 dao/src/main/resources/sql/schema-ts.sql diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index 884afc06c9..f863d0bb2a 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -116,7 +116,7 @@ public class ThingsboardInstallService { log.info("Installing DataBase schema..."); - databaseSchemaService.createDatabaseSchema();//TODO issue 1005 - create both SQL and C* schemas in hybrid mode + databaseSchemaService.createDatabaseSchema(); log.info("Loading system data..."); diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraAbstractDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraAbstractDatabaseSchemaService.java new file mode 100644 index 0000000000..d8d47444e5 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraAbstractDatabaseSchemaService.java @@ -0,0 +1,56 @@ +/** + * 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.service.install; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.thingsboard.server.dao.cassandra.CassandraInstallCluster; +import org.thingsboard.server.service.install.cql.CQLStatementsParser; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +@Slf4j +public abstract class CassandraAbstractDatabaseSchemaService /*implements DatabaseSchemaService*/ { + + private static final String CASSANDRA_DIR = "cassandra"; + + @Autowired + private CassandraInstallCluster cluster; + + @Autowired + private InstallScripts installScripts; + + private final String schemaCql; + + protected CassandraAbstractDatabaseSchemaService(String schemaCql) { + this.schemaCql = schemaCql; + } + + //@Override + public void createDatabaseSchema() throws Exception { + log.info("Installing Cassandra DataBase schema part: " + schemaCql); + Path schemaFile = Paths.get(installScripts.getDataDir(), CASSANDRA_DIR, schemaCql); + loadCql(schemaFile); + + } + + private void loadCql(Path cql) throws Exception { + List statements = new CQLStatementsParser(cql).getStatements(); + statements.forEach(statement -> cluster.getSession().execute(statement)); + } +} diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseSchemaService.java index 6eeeb0a620..0735a59fca 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseSchemaService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseSchemaService.java @@ -19,39 +19,25 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; -import org.thingsboard.server.dao.cassandra.CassandraInstallCluster; -import org.thingsboard.server.dao.util.NoSqlAnyDao; -import org.thingsboard.server.service.install.cql.CQLStatementsParser; - -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; +import org.thingsboard.server.dao.util.NoSqlDao; @Service -@NoSqlAnyDao +@NoSqlDao @Profile("install") @Slf4j public class CassandraDatabaseSchemaService implements DatabaseSchemaService { - private static final String CASSANDRA_DIR = "cassandra"; - private static final String SCHEMA_CQL = "schema.cql"; - @Autowired - private CassandraInstallCluster cluster; + private CassandraEntityDatabaseSchemaService cassandraEntityDatabaseSchemaService; @Autowired - private InstallScripts installScripts; + private CassandraTsDatabaseSchemaService cassandraTsDatabaseSchemaService; + @Override public void createDatabaseSchema() throws Exception { log.info("Installing Cassandra DataBase schema..."); - Path schemaFile = Paths.get(installScripts.getDataDir(), CASSANDRA_DIR, SCHEMA_CQL); - loadCql(schemaFile); - - } - - private void loadCql(Path cql) throws Exception { - List statements = new CQLStatementsParser(cql).getStatements(); - statements.forEach(statement -> cluster.getSession().execute(statement)); + cassandraEntityDatabaseSchemaService.createDatabaseSchema(); + cassandraTsDatabaseSchemaService.createDatabaseSchema(); } } diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraEntityDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraEntityDatabaseSchemaService.java new file mode 100644 index 0000000000..9e4afb1a2a --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraEntityDatabaseSchemaService.java @@ -0,0 +1,25 @@ +/** + * 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.service.install; + +import org.springframework.stereotype.Service; + +@Service +public class CassandraEntityDatabaseSchemaService extends CassandraAbstractDatabaseSchemaService { + public CassandraEntityDatabaseSchemaService() { + super("schema-entities.cql"); + } +} diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseSchemaService.java new file mode 100644 index 0000000000..addc180a8a --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseSchemaService.java @@ -0,0 +1,25 @@ +/** + * 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.service.install; + +import org.springframework.stereotype.Service; + +@Service +public class CassandraTsDatabaseSchemaService extends CassandraAbstractDatabaseSchemaService { + public CassandraTsDatabaseSchemaService() { + super("schema-ts.cql"); + } +} diff --git a/application/src/main/java/org/thingsboard/server/service/install/HybridDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/HybridDatabaseSchemaService.java new file mode 100644 index 0000000000..e689c70109 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/install/HybridDatabaseSchemaService.java @@ -0,0 +1,44 @@ +/** + * 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.service.install; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; +import org.thingsboard.server.dao.util.HybridDao; + +@Service +@Profile("install") +@Slf4j +@HybridDao +public class HybridDatabaseSchemaService implements DatabaseSchemaService { + + @Autowired + private SqlEntityDatabaseSchemaService sqlEntityDatabaseSchemaService; + + @Autowired + private CassandraTsDatabaseSchemaService cassandraTsDatabaseSchemaService; + + + @Override + public void createDatabaseSchema() throws Exception { + log.info("Installing Hybrid SQL/Cassandra DataBase schema..."); + sqlEntityDatabaseSchemaService.createDatabaseSchema(); + cassandraTsDatabaseSchemaService.createDatabaseSchema(); + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlAbstractDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlAbstractDatabaseSchemaService.java new file mode 100644 index 0000000000..f468a6e475 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlAbstractDatabaseSchemaService.java @@ -0,0 +1,65 @@ +/** + * 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.service.install; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.sql.Connection; +import java.sql.DriverManager; + +@Slf4j +public abstract class SqlAbstractDatabaseSchemaService /*implements DatabaseSchemaService*/ { + + private static final String SQL_DIR = "sql"; + + @Value("${spring.datasource.url}") + private String dbUrl; + + @Value("${spring.datasource.username}") + private String dbUserName; + + @Value("${spring.datasource.password}") + private String dbPassword; + + @Autowired + private InstallScripts installScripts; + + private final String schemaSql; + + protected SqlAbstractDatabaseSchemaService(String schemaSql) { + this.schemaSql = schemaSql; + } + + //@Override + public void createDatabaseSchema() throws Exception { + + log.info("Installing SQL DataBase schema part: " + schemaSql); + + Path schemaFile = Paths.get(installScripts.getDataDir(), SQL_DIR, schemaSql); + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { + String sql = new String(Files.readAllBytes(schemaFile), Charset.forName("UTF-8")); + conn.createStatement().execute(sql); //NOSONAR, ignoring because method used to load initial thingsboard database schema + } + + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseSchemaService.java index 1daf66086a..8544b8bbf2 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseSchemaService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseSchemaService.java @@ -17,50 +17,28 @@ package org.thingsboard.server.service.install; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; import org.thingsboard.server.dao.util.SqlDao; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.sql.Connection; -import java.sql.DriverManager; - @Service @Profile("install") @Slf4j @SqlDao public class SqlDatabaseSchemaService implements DatabaseSchemaService { - private static final String SQL_DIR = "sql"; - private static final String SCHEMA_SQL = "schema.sql"; - - @Value("${spring.datasource.url}") - private String dbUrl; - - @Value("${spring.datasource.username}") - private String dbUserName; - - @Value("${spring.datasource.password}") - private String dbPassword; + @Autowired + private SqlEntityDatabaseSchemaService sqlEntityDatabaseSchemaService; @Autowired - private InstallScripts installScripts; + private SqlTsDatabaseSchemaService sqlTsDatabaseSchemaService; + @Override public void createDatabaseSchema() throws Exception { - log.info("Installing SQL DataBase schema..."); - - Path schemaFile = Paths.get(installScripts.getDataDir(), SQL_DIR, SCHEMA_SQL); - try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { - String sql = new String(Files.readAllBytes(schemaFile), Charset.forName("UTF-8")); - conn.createStatement().execute(sql); //NOSONAR, ignoring because method used to load initial thingsboard database schema - } - + sqlEntityDatabaseSchemaService.createDatabaseSchema(); + sqlTsDatabaseSchemaService.createDatabaseSchema(); } } diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlEntityDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlEntityDatabaseSchemaService.java new file mode 100644 index 0000000000..0826099133 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlEntityDatabaseSchemaService.java @@ -0,0 +1,25 @@ +/** + * 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.service.install; + +import org.springframework.stereotype.Service; + +@Service +public class SqlEntityDatabaseSchemaService extends SqlAbstractDatabaseSchemaService { + public SqlEntityDatabaseSchemaService() { + super("schema-entities.sql"); + } +} diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlTsDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlTsDatabaseSchemaService.java new file mode 100644 index 0000000000..6c8f8b5054 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlTsDatabaseSchemaService.java @@ -0,0 +1,25 @@ +/** + * 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.service.install; + +import org.springframework.stereotype.Service; + +@Service +public class SqlTsDatabaseSchemaService extends SqlAbstractDatabaseSchemaService { + public SqlTsDatabaseSchemaService() { + super("schema-ts.sql"); + } +} \ No newline at end of file diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/HybridDao.java b/dao/src/main/java/org/thingsboard/server/dao/util/HybridDao.java new file mode 100644 index 0000000000..2caf8ccace --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/util/HybridDao.java @@ -0,0 +1,22 @@ +/** + * 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.util; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; + +@ConditionalOnExpression("'${database.entity.type}'=='sql' && '${database.ts.type}'=='cassandra'") +public @interface HybridDao { +} diff --git a/dao/src/main/resources/cassandra/schema-entities.cql b/dao/src/main/resources/cassandra/schema-entities.cql new file mode 100644 index 0000000000..e1a21ebc1a --- /dev/null +++ b/dao/src/main/resources/cassandra/schema-entities.cql @@ -0,0 +1,605 @@ +-- +-- 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. +-- + +CREATE KEYSPACE IF NOT EXISTS thingsboard +WITH replication = { + 'class' : 'SimpleStrategy', + 'replication_factor' : 1 +}; + +CREATE TABLE IF NOT EXISTS thingsboard.user ( + id timeuuid, + tenant_id timeuuid, + customer_id timeuuid, + email text, + search_text text, + authority text, + first_name text, + last_name text, + additional_info text, + PRIMARY KEY (id, tenant_id, customer_id, authority) +); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.user_by_email AS + SELECT * + from thingsboard.user + WHERE email IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND id IS NOT NULL AND authority IS NOT + NULL + PRIMARY KEY ( email, tenant_id, customer_id, id, authority ); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.user_by_tenant_and_search_text AS + SELECT * + from thingsboard.user + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND authority IS NOT NULL AND search_text IS NOT NULL AND id + IS NOT NULL + PRIMARY KEY ( tenant_id, customer_id, authority, search_text, id ) + WITH CLUSTERING ORDER BY ( customer_id DESC, authority DESC, search_text ASC, id DESC ); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.user_by_customer_and_search_text AS + SELECT * + from thingsboard.user + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND authority IS NOT NULL AND search_text IS NOT NULL AND id + IS NOT NULL + PRIMARY KEY ( customer_id, tenant_id, authority, search_text, id ) + WITH CLUSTERING ORDER BY ( tenant_id DESC, authority DESC, search_text ASC, id DESC ); + +CREATE TABLE IF NOT EXISTS thingsboard.user_credentials ( + id timeuuid PRIMARY KEY, + user_id timeuuid, + enabled boolean, + password text, + activate_token text, + reset_token text +); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.user_credentials_by_user AS + SELECT * + from thingsboard.user_credentials + WHERE user_id IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( user_id, id ); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.user_credentials_by_activate_token AS + SELECT * + from thingsboard.user_credentials + WHERE activate_token IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( activate_token, id ); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.user_credentials_by_reset_token AS + SELECT * + from thingsboard.user_credentials + WHERE reset_token IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( reset_token, id ); + +CREATE TABLE IF NOT EXISTS thingsboard.admin_settings ( + id timeuuid PRIMARY KEY, + key text, + json_value text +); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.admin_settings_by_key AS + SELECT * + from thingsboard.admin_settings + WHERE key IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( key, id ) + WITH CLUSTERING ORDER BY ( id DESC ); + +CREATE TABLE IF NOT EXISTS thingsboard.tenant ( + id timeuuid, + title text, + search_text text, + region text, + country text, + state text, + city text, + address text, + address2 text, + zip text, + phone text, + email text, + additional_info text, + PRIMARY KEY (id, region) +); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.tenant_by_region_and_search_text AS + SELECT * + from thingsboard.tenant + WHERE region IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( region, search_text, id ) + WITH CLUSTERING ORDER BY ( search_text ASC, id DESC ); + +CREATE TABLE IF NOT EXISTS thingsboard.customer ( + id timeuuid, + tenant_id timeuuid, + title text, + search_text text, + country text, + state text, + city text, + address text, + address2 text, + zip text, + phone text, + email text, + additional_info text, + PRIMARY KEY (id, tenant_id) +); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.customer_by_tenant_and_title AS + SELECT * + from thingsboard.customer + WHERE tenant_id IS NOT NULL AND title IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( tenant_id, title, id ) + WITH CLUSTERING ORDER BY ( title ASC, id DESC ); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.customer_by_tenant_and_search_text AS + SELECT * + from thingsboard.customer + WHERE tenant_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( tenant_id, search_text, id ) + WITH CLUSTERING ORDER BY ( search_text ASC, id DESC ); + +CREATE TABLE IF NOT EXISTS thingsboard.device ( + id timeuuid, + tenant_id timeuuid, + customer_id timeuuid, + name text, + type text, + search_text text, + additional_info text, + PRIMARY KEY (id, tenant_id, customer_id, type) +); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_tenant_and_name AS + SELECT * + from thingsboard.device + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( tenant_id, name, id, customer_id, type) + WITH CLUSTERING ORDER BY ( name ASC, id DESC, customer_id DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_tenant_and_search_text AS + SELECT * + from thingsboard.device + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( tenant_id, search_text, id, customer_id, type) + WITH CLUSTERING ORDER BY ( search_text ASC, id DESC, customer_id DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_tenant_by_type_and_search_text AS + SELECT * + from thingsboard.device + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( tenant_id, type, search_text, id, customer_id) + WITH CLUSTERING ORDER BY ( type ASC, search_text ASC, id DESC, customer_id DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_customer_and_search_text AS + SELECT * + from thingsboard.device + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( customer_id, tenant_id, search_text, id, type ) + WITH CLUSTERING ORDER BY ( tenant_id DESC, search_text ASC, id DESC ); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_customer_by_type_and_search_text AS + SELECT * + from thingsboard.device + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( customer_id, tenant_id, type, search_text, id ) + WITH CLUSTERING ORDER BY ( tenant_id DESC, type ASC, search_text ASC, id DESC ); + +CREATE TABLE IF NOT EXISTS thingsboard.device_credentials ( + id timeuuid PRIMARY KEY, + device_id timeuuid, + credentials_type text, + credentials_id text, + credentials_value text +); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_credentials_by_device AS + SELECT * + from thingsboard.device_credentials + WHERE device_id IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( device_id, id ); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_credentials_by_credentials_id AS + SELECT * + from thingsboard.device_credentials + WHERE credentials_id IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( credentials_id, id ); + +CREATE TABLE IF NOT EXISTS thingsboard.asset ( + id timeuuid, + tenant_id timeuuid, + customer_id timeuuid, + name text, + type text, + search_text text, + additional_info text, + PRIMARY KEY (id, tenant_id, customer_id, type) +); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_tenant_and_name AS + SELECT * + from thingsboard.asset + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( tenant_id, name, id, customer_id, type) + WITH CLUSTERING ORDER BY ( name ASC, id DESC, customer_id DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_tenant_and_search_text AS + SELECT * + from thingsboard.asset + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( tenant_id, search_text, id, customer_id, type) + WITH CLUSTERING ORDER BY ( search_text ASC, id DESC, customer_id DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_tenant_by_type_and_search_text AS + SELECT * + from thingsboard.asset + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( tenant_id, type, search_text, id, customer_id) + WITH CLUSTERING ORDER BY ( type ASC, search_text ASC, id DESC, customer_id DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_customer_and_search_text AS + SELECT * + from thingsboard.asset + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( customer_id, tenant_id, search_text, id, type ) + WITH CLUSTERING ORDER BY ( tenant_id DESC, search_text ASC, id DESC ); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_customer_by_type_and_search_text AS + SELECT * + from thingsboard.asset + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( customer_id, tenant_id, type, search_text, id ) + WITH CLUSTERING ORDER BY ( tenant_id DESC, type ASC, search_text ASC, id DESC ); + +CREATE TABLE IF NOT EXISTS thingsboard.entity_subtype ( + tenant_id timeuuid, + entity_type text, // (DEVICE, ASSET) + type text, + PRIMARY KEY (tenant_id, entity_type, type) +); + +CREATE TABLE IF NOT EXISTS thingsboard.alarm ( + id timeuuid, + tenant_id timeuuid, + type text, + originator_id timeuuid, + originator_type text, + severity text, + status text, + start_ts bigint, + end_ts bigint, + ack_ts bigint, + clear_ts bigint, + details text, + propagate boolean, + PRIMARY KEY ((tenant_id, originator_id, originator_type), type, id) +) WITH CLUSTERING ORDER BY ( type ASC, id DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.alarm_by_id AS + SELECT * + from thingsboard.alarm + WHERE tenant_id IS NOT NULL AND originator_id IS NOT NULL AND originator_type IS NOT NULL AND type IS NOT NULL + AND type IS NOT NULL AND id IS NOT NULL + PRIMARY KEY (id, tenant_id, originator_id, originator_type, type) + WITH CLUSTERING ORDER BY ( tenant_id ASC, originator_id ASC, originator_type ASC, type ASC); + +CREATE TABLE IF NOT EXISTS thingsboard.relation ( + from_id timeuuid, + from_type text, + to_id timeuuid, + to_type text, + relation_type_group text, + relation_type text, + additional_info text, + PRIMARY KEY ((from_id, from_type), relation_type_group, relation_type, to_id, to_type) +) WITH CLUSTERING ORDER BY ( relation_type_group ASC, relation_type ASC, to_id ASC, to_type ASC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.relation_by_type_and_child_type AS + SELECT * + from thingsboard.relation + WHERE from_id IS NOT NULL AND from_type IS NOT NULL AND relation_type_group IS NOT NULL AND relation_type IS NOT NULL AND to_id IS NOT NULL AND to_type IS NOT NULL + PRIMARY KEY ((from_id, from_type), relation_type_group, relation_type, to_type, to_id) + WITH CLUSTERING ORDER BY ( relation_type_group ASC, relation_type ASC, to_type ASC, to_id DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.reverse_relation AS + SELECT * + from thingsboard.relation + WHERE from_id IS NOT NULL AND from_type IS NOT NULL AND relation_type_group IS NOT NULL AND relation_type IS NOT NULL AND to_id IS NOT NULL AND to_type IS NOT NULL + PRIMARY KEY ((to_id, to_type), relation_type_group, relation_type, from_id, from_type) + WITH CLUSTERING ORDER BY ( relation_type_group ASC, relation_type ASC, from_id ASC, from_type ASC); + +CREATE TABLE IF NOT EXISTS thingsboard.widgets_bundle ( + id timeuuid, + tenant_id timeuuid, + alias text, + title text, + search_text text, + image blob, + PRIMARY KEY (id, tenant_id) +); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.widgets_bundle_by_tenant_and_search_text AS + SELECT * + from thingsboard.widgets_bundle + WHERE tenant_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( tenant_id, search_text, id ) + WITH CLUSTERING ORDER BY ( search_text ASC, id DESC ); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.widgets_bundle_by_tenant_and_alias AS + SELECT * + from thingsboard.widgets_bundle + WHERE tenant_id IS NOT NULL AND alias IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( tenant_id, alias, id ) + WITH CLUSTERING ORDER BY ( alias ASC, id DESC ); + +CREATE TABLE IF NOT EXISTS thingsboard.widget_type ( + id timeuuid, + tenant_id timeuuid, + bundle_alias text, + alias text, + name text, + descriptor text, + PRIMARY KEY (id, tenant_id, bundle_alias) +); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.widget_type_by_tenant_and_aliases AS + SELECT * + from thingsboard.widget_type + WHERE tenant_id IS NOT NULL AND bundle_alias IS NOT NULL AND alias IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( tenant_id, bundle_alias, alias, id ) + WITH CLUSTERING ORDER BY ( bundle_alias ASC, alias ASC, id DESC ); + +CREATE TABLE IF NOT EXISTS thingsboard.dashboard ( + id timeuuid, + tenant_id timeuuid, + title text, + search_text text, + assigned_customers text, + configuration text, + PRIMARY KEY (id, tenant_id) +); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.dashboard_by_tenant_and_search_text AS + SELECT * + from thingsboard.dashboard + WHERE tenant_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( tenant_id, search_text, id ) + WITH CLUSTERING ORDER BY ( search_text ASC, id DESC ); + +CREATE TABLE IF NOT EXISTS thingsboard.attributes_kv_cf ( + entity_type text, // (DEVICE, CUSTOMER, TENANT) + entity_id timeuuid, + attribute_type text, // (CLIENT_SIDE, SHARED, SERVER_SIDE) + attribute_key text, + bool_v boolean, + str_v text, + long_v bigint, + dbl_v double, + last_update_ts bigint, + PRIMARY KEY ((entity_type, entity_id, attribute_type), attribute_key) +) WITH compaction = { 'class' : 'LeveledCompactionStrategy' }; + +CREATE TABLE IF NOT EXISTS thingsboard.component_descriptor ( + id timeuuid, + type text, + scope text, + name text, + search_text text, + clazz text, + configuration_descriptor text, + actions text, + PRIMARY KEY (clazz, id, type, scope) +); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.component_desc_by_type_search_text AS + SELECT * + from thingsboard.component_descriptor + WHERE type IS NOT NULL AND scope IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL AND clazz IS NOT NULL + PRIMARY KEY ( type, search_text, id, clazz, scope) + WITH CLUSTERING ORDER BY ( search_text DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.component_desc_by_scope_type_search_text AS + SELECT * + from thingsboard.component_descriptor + WHERE type IS NOT NULL AND scope IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL AND clazz IS NOT NULL + PRIMARY KEY ( (scope, type), search_text, id, clazz) + WITH CLUSTERING ORDER BY ( search_text DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.component_desc_by_id AS + SELECT * + from thingsboard.component_descriptor + WHERE type IS NOT NULL AND scope IS NOT NULL AND id IS NOT NULL AND clazz IS NOT NULL + PRIMARY KEY ( id, clazz, scope, type ) + WITH CLUSTERING ORDER BY ( clazz ASC, scope ASC, type DESC); + +CREATE TABLE IF NOT EXISTS thingsboard.event ( + tenant_id timeuuid, // tenant or system + id timeuuid, + event_type text, + event_uid text, + entity_type text, + entity_id timeuuid, + body text, + PRIMARY KEY ((tenant_id, entity_type, entity_id), event_type, event_uid) +); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.event_by_type_and_id AS + SELECT * + FROM thingsboard.event + WHERE tenant_id IS NOT NULL AND entity_type IS NOT NULL AND entity_id IS NOT NULL AND id IS NOT NULL + AND event_type IS NOT NULL AND event_uid IS NOT NULL + PRIMARY KEY ((tenant_id, entity_type, entity_id), event_type, id, event_uid) + WITH CLUSTERING ORDER BY (event_type ASC, id ASC, event_uid ASC); + + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.event_by_id AS + SELECT * + FROM thingsboard.event + WHERE tenant_id IS NOT NULL AND entity_type IS NOT NULL AND entity_id IS NOT NULL AND id IS NOT NULL + AND event_type IS NOT NULL AND event_uid IS NOT NULL + PRIMARY KEY ((tenant_id, entity_type, entity_id), id, event_type, event_uid) + WITH CLUSTERING ORDER BY (id ASC, event_type ASC, event_uid ASC); + +CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_entity_id ( + tenant_id timeuuid, + id timeuuid, + customer_id timeuuid, + entity_id timeuuid, + entity_type text, + entity_name text, + user_id timeuuid, + user_name text, + action_type text, + action_data text, + action_status text, + action_failure_details text, + PRIMARY KEY ((tenant_id, entity_id, entity_type), id) +); + +CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_customer_id ( + tenant_id timeuuid, + id timeuuid, + customer_id timeuuid, + entity_id timeuuid, + entity_type text, + entity_name text, + user_id timeuuid, + user_name text, + action_type text, + action_data text, + action_status text, + action_failure_details text, + PRIMARY KEY ((tenant_id, customer_id), id) +); + +CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_user_id ( + tenant_id timeuuid, + id timeuuid, + customer_id timeuuid, + entity_id timeuuid, + entity_type text, + entity_name text, + user_id timeuuid, + user_name text, + action_type text, + action_data text, + action_status text, + action_failure_details text, + PRIMARY KEY ((tenant_id, user_id), id) +); + +CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_tenant_id ( + tenant_id timeuuid, + id timeuuid, + partition bigint, + customer_id timeuuid, + entity_id timeuuid, + entity_type text, + entity_name text, + user_id timeuuid, + user_name text, + action_type text, + action_data text, + action_status text, + action_failure_details text, + PRIMARY KEY ((tenant_id, partition), id) +); + +CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_tenant_id_partitions ( + tenant_id timeuuid, + partition bigint, + PRIMARY KEY (( tenant_id ), partition) +) WITH CLUSTERING ORDER BY ( partition ASC ) +AND compaction = { 'class' : 'LeveledCompactionStrategy' }; + +CREATE TABLE IF NOT EXISTS thingsboard.msg_queue ( + node_id timeuuid, + cluster_partition bigint, + ts_partition bigint, + ts bigint, + msg blob, + PRIMARY KEY ((node_id, cluster_partition, ts_partition), ts)) +WITH CLUSTERING ORDER BY (ts DESC) +AND compaction = { + 'class': 'org.apache.cassandra.db.compaction.DateTieredCompactionStrategy', + 'min_threshold': '5', + 'base_time_seconds': '43200', + 'max_window_size_seconds': '43200', + 'tombstone_threshold': '0.9', + 'unchecked_tombstone_compaction': 'true' +}; + +CREATE TABLE IF NOT EXISTS thingsboard.msg_ack_queue ( + node_id timeuuid, + cluster_partition bigint, + ts_partition bigint, + msg_id timeuuid, + PRIMARY KEY ((node_id, cluster_partition, ts_partition), msg_id)) +WITH CLUSTERING ORDER BY (msg_id DESC) +AND compaction = { + 'class': 'org.apache.cassandra.db.compaction.DateTieredCompactionStrategy', + 'min_threshold': '5', + 'base_time_seconds': '43200', + 'max_window_size_seconds': '43200', + 'tombstone_threshold': '0.9', + 'unchecked_tombstone_compaction': 'true' +}; + +CREATE TABLE IF NOT EXISTS thingsboard.processed_msg_partitions ( + node_id timeuuid, + cluster_partition bigint, + ts_partition bigint, + PRIMARY KEY ((node_id, cluster_partition), ts_partition)) +WITH CLUSTERING ORDER BY (ts_partition DESC) +AND compaction = { + 'class': 'org.apache.cassandra.db.compaction.DateTieredCompactionStrategy', + 'min_threshold': '5', + 'base_time_seconds': '43200', + 'max_window_size_seconds': '43200', + 'tombstone_threshold': '0.9', + 'unchecked_tombstone_compaction': 'true' +}; + +CREATE TABLE IF NOT EXISTS thingsboard.rule_chain ( + id uuid, + tenant_id uuid, + name text, + search_text text, + first_rule_node_id uuid, + root boolean, + debug_mode boolean, + configuration text, + additional_info text, + PRIMARY KEY (id, tenant_id) +); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.rule_chain_by_tenant_and_search_text AS + SELECT * + from thingsboard.rule_chain + WHERE tenant_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + PRIMARY KEY ( tenant_id, search_text, id ) + WITH CLUSTERING ORDER BY ( search_text ASC, id DESC ); + +CREATE TABLE IF NOT EXISTS thingsboard.rule_node ( + id uuid, + rule_chain_id uuid, + type text, + name text, + debug_mode boolean, + search_text text, + configuration text, + additional_info text, + PRIMARY KEY (id) +); diff --git a/dao/src/main/resources/cassandra/schema-ts.cql b/dao/src/main/resources/cassandra/schema-ts.cql new file mode 100644 index 0000000000..a5c5ec2ff1 --- /dev/null +++ b/dao/src/main/resources/cassandra/schema-ts.cql @@ -0,0 +1,55 @@ +-- +-- 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. +-- + +CREATE KEYSPACE IF NOT EXISTS thingsboard +WITH replication = { + 'class' : 'SimpleStrategy', + 'replication_factor' : 1 +}; + +CREATE TABLE IF NOT EXISTS thingsboard.ts_kv_cf ( + entity_type text, // (DEVICE, CUSTOMER, TENANT) + entity_id timeuuid, + key text, + partition bigint, + ts bigint, + bool_v boolean, + str_v text, + long_v bigint, + dbl_v double, + PRIMARY KEY (( entity_type, entity_id, key, partition ), ts) +); + +CREATE TABLE IF NOT EXISTS thingsboard.ts_kv_partitions_cf ( + entity_type text, // (DEVICE, CUSTOMER, TENANT) + entity_id timeuuid, + key text, + partition bigint, + PRIMARY KEY (( entity_type, entity_id, key ), partition) +) WITH CLUSTERING ORDER BY ( partition ASC ) + AND compaction = { 'class' : 'LeveledCompactionStrategy' }; + +CREATE TABLE IF NOT EXISTS thingsboard.ts_kv_latest_cf ( + entity_type text, // (DEVICE, CUSTOMER, TENANT) + entity_id timeuuid, + key text, + ts bigint, + bool_v boolean, + str_v text, + long_v bigint, + dbl_v double, + PRIMARY KEY (( entity_type, entity_id ), key) +) WITH compaction = { 'class' : 'LeveledCompactionStrategy' }; diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql new file mode 100644 index 0000000000..20efec8cd6 --- /dev/null +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -0,0 +1,229 @@ +-- +-- 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. +-- + + +CREATE TABLE IF NOT EXISTS admin_settings ( + id varchar(31) NOT NULL CONSTRAINT admin_settings_pkey PRIMARY KEY, + json_value varchar, + key varchar(255) +); + +CREATE TABLE IF NOT EXISTS alarm ( + id varchar(31) NOT NULL CONSTRAINT alarm_pkey PRIMARY KEY, + ack_ts bigint, + clear_ts bigint, + additional_info varchar, + end_ts bigint, + originator_id varchar(31), + originator_type integer, + propagate boolean, + severity varchar(255), + start_ts bigint, + status varchar(255), + tenant_id varchar(31), + type varchar(255) +); + +CREATE TABLE IF NOT EXISTS asset ( + id varchar(31) NOT NULL CONSTRAINT asset_pkey PRIMARY KEY, + additional_info varchar, + customer_id varchar(31), + name varchar(255), + search_text varchar(255), + tenant_id varchar(31), + type varchar(255) +); + +CREATE TABLE IF NOT EXISTS audit_log ( + id varchar(31) NOT NULL CONSTRAINT audit_log_pkey PRIMARY KEY, + tenant_id varchar(31), + customer_id varchar(31), + entity_id varchar(31), + entity_type varchar(255), + entity_name varchar(255), + user_id varchar(31), + user_name varchar(255), + action_type varchar(255), + action_data varchar(1000000), + action_status varchar(255), + action_failure_details varchar(1000000) +); + +CREATE TABLE IF NOT EXISTS attribute_kv ( + entity_type varchar(255), + entity_id varchar(31), + attribute_type varchar(255), + attribute_key varchar(255), + bool_v boolean, + str_v varchar(10000000), + long_v bigint, + dbl_v double precision, + last_update_ts bigint, + CONSTRAINT attribute_kv_unq_key UNIQUE (entity_type, entity_id, attribute_type, attribute_key) +); + +CREATE TABLE IF NOT EXISTS component_descriptor ( + id varchar(31) NOT NULL CONSTRAINT component_descriptor_pkey PRIMARY KEY, + actions varchar(255), + clazz varchar, + configuration_descriptor varchar, + name varchar(255), + scope varchar(255), + search_text varchar(255), + type varchar(255) +); + +CREATE TABLE IF NOT EXISTS customer ( + id varchar(31) NOT NULL CONSTRAINT customer_pkey PRIMARY KEY, + additional_info varchar, + address varchar, + address2 varchar, + city varchar(255), + country varchar(255), + email varchar(255), + phone varchar(255), + search_text varchar(255), + state varchar(255), + tenant_id varchar(31), + title varchar(255), + zip varchar(255) +); + +CREATE TABLE IF NOT EXISTS dashboard ( + id varchar(31) NOT NULL CONSTRAINT dashboard_pkey PRIMARY KEY, + configuration varchar(10000000), + assigned_customers varchar(1000000), + search_text varchar(255), + tenant_id varchar(31), + title varchar(255) +); + +CREATE TABLE IF NOT EXISTS device ( + id varchar(31) NOT NULL CONSTRAINT device_pkey PRIMARY KEY, + additional_info varchar, + customer_id varchar(31), + type varchar(255), + name varchar(255), + search_text varchar(255), + tenant_id varchar(31) +); + +CREATE TABLE IF NOT EXISTS device_credentials ( + id varchar(31) NOT NULL CONSTRAINT device_credentials_pkey PRIMARY KEY, + credentials_id varchar, + credentials_type varchar(255), + credentials_value varchar, + device_id varchar(31) +); + +CREATE TABLE IF NOT EXISTS event ( + id varchar(31) NOT NULL CONSTRAINT event_pkey PRIMARY KEY, + body varchar, + entity_id varchar(31), + entity_type varchar(255), + event_type varchar(255), + event_uid varchar(255), + tenant_id varchar(31), + CONSTRAINT event_unq_key UNIQUE (tenant_id, entity_type, entity_id, event_type, event_uid) +); + +CREATE TABLE IF NOT EXISTS relation ( + from_id varchar(31), + from_type varchar(255), + to_id varchar(31), + to_type varchar(255), + relation_type_group varchar(255), + relation_type varchar(255), + additional_info varchar, + CONSTRAINT relation_unq_key UNIQUE (from_id, from_type, relation_type_group, relation_type, to_id, to_type) +); + +CREATE TABLE IF NOT EXISTS tb_user ( + id varchar(31) NOT NULL CONSTRAINT tb_user_pkey PRIMARY KEY, + additional_info varchar, + authority varchar(255), + customer_id varchar(31), + email varchar(255) UNIQUE, + first_name varchar(255), + last_name varchar(255), + search_text varchar(255), + tenant_id varchar(31) +); + +CREATE TABLE IF NOT EXISTS tenant ( + id varchar(31) NOT NULL CONSTRAINT tenant_pkey PRIMARY KEY, + additional_info varchar, + address varchar, + address2 varchar, + city varchar(255), + country varchar(255), + email varchar(255), + phone varchar(255), + region varchar(255), + search_text varchar(255), + state varchar(255), + title varchar(255), + zip varchar(255) +); + +CREATE TABLE IF NOT EXISTS user_credentials ( + id varchar(31) NOT NULL CONSTRAINT user_credentials_pkey PRIMARY KEY, + activate_token varchar(255) UNIQUE, + enabled boolean, + password varchar(255), + reset_token varchar(255) UNIQUE, + user_id varchar(31) UNIQUE +); + +CREATE TABLE IF NOT EXISTS widget_type ( + id varchar(31) NOT NULL CONSTRAINT widget_type_pkey PRIMARY KEY, + alias varchar(255), + bundle_alias varchar(255), + descriptor varchar(1000000), + name varchar(255), + tenant_id varchar(31) +); + +CREATE TABLE IF NOT EXISTS widgets_bundle ( + id varchar(31) NOT NULL CONSTRAINT widgets_bundle_pkey PRIMARY KEY, + alias varchar(255), + search_text varchar(255), + tenant_id varchar(31), + title varchar(255) +); + +CREATE TABLE IF NOT EXISTS rule_chain ( + id varchar(31) NOT NULL CONSTRAINT rule_chain_pkey PRIMARY KEY, + additional_info varchar, + configuration varchar(10000000), + name varchar(255), + first_rule_node_id varchar(31), + root boolean, + debug_mode boolean, + search_text varchar(255), + tenant_id varchar(31) +); + +CREATE TABLE IF NOT EXISTS rule_node ( + id varchar(31) NOT NULL CONSTRAINT rule_node_pkey PRIMARY KEY, + rule_chain_id varchar(31), + additional_info varchar, + configuration varchar(10000000), + type varchar(255), + name varchar(255), + debug_mode boolean, + search_text varchar(255) +); diff --git a/dao/src/main/resources/sql/schema-ts.sql b/dao/src/main/resources/sql/schema-ts.sql new file mode 100644 index 0000000000..53bc15acc3 --- /dev/null +++ b/dao/src/main/resources/sql/schema-ts.sql @@ -0,0 +1,39 @@ +-- +-- 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. +-- + +CREATE TABLE IF NOT EXISTS ts_kv ( + entity_type varchar(255) NOT NULL, + entity_id varchar(31) NOT NULL, + key varchar(255) NOT NULL, + ts bigint NOT NULL, + bool_v boolean, + str_v varchar(10000000), + long_v bigint, + dbl_v double precision, + CONSTRAINT ts_kv_unq_key UNIQUE (entity_type, entity_id, key, ts) +); + +CREATE TABLE IF NOT EXISTS ts_kv_latest ( + entity_type varchar(255) NOT NULL, + entity_id varchar(31) NOT NULL, + key varchar(255) NOT NULL, + ts bigint NOT NULL, + bool_v boolean, + str_v varchar(10000000), + long_v bigint, + dbl_v double precision, + CONSTRAINT ts_kv_latest_unq_key UNIQUE (entity_type, entity_id, key) +); From 90e0d8965bc9b2d8886a6a9dbc87269dae4b02a0 Mon Sep 17 00:00:00 2001 From: hagaic Date: Wed, 22 Aug 2018 04:27:12 +0300 Subject: [PATCH 004/118] install hybrid db schema (simplified) --- .../install/ThingsboardInstallService.java | 16 +++++-- ...assandraAbstractDatabaseSchemaService.java | 4 +- .../CassandraDatabaseSchemaService.java | 43 ------------------ .../CassandraEntityDatabaseSchemaService.java | 5 ++- .../CassandraTsDatabaseSchemaService.java | 5 ++- .../install/EntityDatabaseSchemaService.java | 4 ++ .../install/HybridDatabaseSchemaService.java | 44 ------------------- .../SqlAbstractDatabaseSchemaService.java | 4 +- .../install/SqlDatabaseSchemaService.java | 44 ------------------- .../SqlEntityDatabaseSchemaService.java | 5 ++- .../install/SqlTsDatabaseSchemaService.java | 5 ++- .../install/TsDatabaseSchemaService.java | 4 ++ 12 files changed, 40 insertions(+), 143 deletions(-) delete mode 100644 application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseSchemaService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/install/EntityDatabaseSchemaService.java delete mode 100644 application/src/main/java/org/thingsboard/server/service/install/HybridDatabaseSchemaService.java delete mode 100644 application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseSchemaService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/install/TsDatabaseSchemaService.java diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index f863d0bb2a..2a55abff65 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -24,9 +24,10 @@ import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; import org.thingsboard.server.service.component.ComponentDiscoveryService; import org.thingsboard.server.service.install.DataUpdateService; -import org.thingsboard.server.service.install.DatabaseSchemaService; import org.thingsboard.server.service.install.DatabaseUpgradeService; +import org.thingsboard.server.service.install.EntityDatabaseSchemaService; import org.thingsboard.server.service.install.SystemDataLoaderService; +import org.thingsboard.server.service.install.TsDatabaseSchemaService; @Service @Profile("install") @@ -43,7 +44,10 @@ public class ThingsboardInstallService { private Boolean loadDemo; @Autowired - private DatabaseSchemaService databaseSchemaService; + private EntityDatabaseSchemaService entityDatabaseSchemaService; + + @Autowired + private TsDatabaseSchemaService tsDatabaseSchemaService; @Autowired private DatabaseUpgradeService databaseUpgradeService; @@ -114,9 +118,13 @@ public class ThingsboardInstallService { log.info("Starting ThingsBoard Installation..."); - log.info("Installing DataBase schema..."); + log.info("Installing DataBase schema for entities..."); + + entityDatabaseSchemaService.createDatabaseSchema(); + + log.info("Installing DataBase schema for timeseries..."); - databaseSchemaService.createDatabaseSchema(); + tsDatabaseSchemaService.createDatabaseSchema(); log.info("Loading system data..."); diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraAbstractDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraAbstractDatabaseSchemaService.java index d8d47444e5..10559ba2d2 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/CassandraAbstractDatabaseSchemaService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraAbstractDatabaseSchemaService.java @@ -25,7 +25,7 @@ import java.nio.file.Paths; import java.util.List; @Slf4j -public abstract class CassandraAbstractDatabaseSchemaService /*implements DatabaseSchemaService*/ { +public abstract class CassandraAbstractDatabaseSchemaService implements DatabaseSchemaService { private static final String CASSANDRA_DIR = "cassandra"; @@ -41,7 +41,7 @@ public abstract class CassandraAbstractDatabaseSchemaService /*implements Databa this.schemaCql = schemaCql; } - //@Override + @Override public void createDatabaseSchema() throws Exception { log.info("Installing Cassandra DataBase schema part: " + schemaCql); Path schemaFile = Paths.get(installScripts.getDataDir(), CASSANDRA_DIR, schemaCql); diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseSchemaService.java deleted file mode 100644 index 0735a59fca..0000000000 --- a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseSchemaService.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * 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.service.install; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; -import org.springframework.stereotype.Service; -import org.thingsboard.server.dao.util.NoSqlDao; - -@Service -@NoSqlDao -@Profile("install") -@Slf4j -public class CassandraDatabaseSchemaService implements DatabaseSchemaService { - - @Autowired - private CassandraEntityDatabaseSchemaService cassandraEntityDatabaseSchemaService; - - @Autowired - private CassandraTsDatabaseSchemaService cassandraTsDatabaseSchemaService; - - - @Override - public void createDatabaseSchema() throws Exception { - log.info("Installing Cassandra DataBase schema..."); - cassandraEntityDatabaseSchemaService.createDatabaseSchema(); - cassandraTsDatabaseSchemaService.createDatabaseSchema(); - } -} diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraEntityDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraEntityDatabaseSchemaService.java index 9e4afb1a2a..7937ef23be 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/CassandraEntityDatabaseSchemaService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraEntityDatabaseSchemaService.java @@ -16,9 +16,12 @@ package org.thingsboard.server.service.install; import org.springframework.stereotype.Service; +import org.thingsboard.server.dao.util.NoSqlDao; @Service -public class CassandraEntityDatabaseSchemaService extends CassandraAbstractDatabaseSchemaService { +@NoSqlDao +public class CassandraEntityDatabaseSchemaService extends CassandraAbstractDatabaseSchemaService + implements EntityDatabaseSchemaService { public CassandraEntityDatabaseSchemaService() { super("schema-entities.cql"); } diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseSchemaService.java index addc180a8a..ba18b57ff1 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseSchemaService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseSchemaService.java @@ -16,9 +16,12 @@ package org.thingsboard.server.service.install; import org.springframework.stereotype.Service; +import org.thingsboard.server.dao.util.NoSqlTsDao; @Service -public class CassandraTsDatabaseSchemaService extends CassandraAbstractDatabaseSchemaService { +@NoSqlTsDao +public class CassandraTsDatabaseSchemaService extends CassandraAbstractDatabaseSchemaService + implements TsDatabaseSchemaService { public CassandraTsDatabaseSchemaService() { super("schema-ts.cql"); } diff --git a/application/src/main/java/org/thingsboard/server/service/install/EntityDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/EntityDatabaseSchemaService.java new file mode 100644 index 0000000000..1d0ddc34a4 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/install/EntityDatabaseSchemaService.java @@ -0,0 +1,4 @@ +package org.thingsboard.server.service.install; + +public interface EntityDatabaseSchemaService extends DatabaseSchemaService { +} diff --git a/application/src/main/java/org/thingsboard/server/service/install/HybridDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/HybridDatabaseSchemaService.java deleted file mode 100644 index e689c70109..0000000000 --- a/application/src/main/java/org/thingsboard/server/service/install/HybridDatabaseSchemaService.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * 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.service.install; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; -import org.springframework.stereotype.Service; -import org.thingsboard.server.dao.util.HybridDao; - -@Service -@Profile("install") -@Slf4j -@HybridDao -public class HybridDatabaseSchemaService implements DatabaseSchemaService { - - @Autowired - private SqlEntityDatabaseSchemaService sqlEntityDatabaseSchemaService; - - @Autowired - private CassandraTsDatabaseSchemaService cassandraTsDatabaseSchemaService; - - - @Override - public void createDatabaseSchema() throws Exception { - log.info("Installing Hybrid SQL/Cassandra DataBase schema..."); - sqlEntityDatabaseSchemaService.createDatabaseSchema(); - cassandraTsDatabaseSchemaService.createDatabaseSchema(); - } - -} diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlAbstractDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlAbstractDatabaseSchemaService.java index f468a6e475..4a39b8f60b 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlAbstractDatabaseSchemaService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlAbstractDatabaseSchemaService.java @@ -27,7 +27,7 @@ import java.sql.Connection; import java.sql.DriverManager; @Slf4j -public abstract class SqlAbstractDatabaseSchemaService /*implements DatabaseSchemaService*/ { +public abstract class SqlAbstractDatabaseSchemaService implements DatabaseSchemaService { private static final String SQL_DIR = "sql"; @@ -49,7 +49,7 @@ public abstract class SqlAbstractDatabaseSchemaService /*implements DatabaseSche this.schemaSql = schemaSql; } - //@Override + @Override public void createDatabaseSchema() throws Exception { log.info("Installing SQL DataBase schema part: " + schemaSql); diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseSchemaService.java deleted file mode 100644 index 8544b8bbf2..0000000000 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseSchemaService.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * 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.service.install; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; -import org.springframework.stereotype.Service; -import org.thingsboard.server.dao.util.SqlDao; - -@Service -@Profile("install") -@Slf4j -@SqlDao -public class SqlDatabaseSchemaService implements DatabaseSchemaService { - - @Autowired - private SqlEntityDatabaseSchemaService sqlEntityDatabaseSchemaService; - - @Autowired - private SqlTsDatabaseSchemaService sqlTsDatabaseSchemaService; - - - @Override - public void createDatabaseSchema() throws Exception { - log.info("Installing SQL DataBase schema..."); - sqlEntityDatabaseSchemaService.createDatabaseSchema(); - sqlTsDatabaseSchemaService.createDatabaseSchema(); - } - -} diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlEntityDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlEntityDatabaseSchemaService.java index 0826099133..16453c6ebb 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlEntityDatabaseSchemaService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlEntityDatabaseSchemaService.java @@ -16,9 +16,12 @@ package org.thingsboard.server.service.install; import org.springframework.stereotype.Service; +import org.thingsboard.server.dao.util.SqlDao; @Service -public class SqlEntityDatabaseSchemaService extends SqlAbstractDatabaseSchemaService { +@SqlDao +public class SqlEntityDatabaseSchemaService extends SqlAbstractDatabaseSchemaService + implements EntityDatabaseSchemaService { public SqlEntityDatabaseSchemaService() { super("schema-entities.sql"); } diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlTsDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlTsDatabaseSchemaService.java index 6c8f8b5054..82daf904df 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlTsDatabaseSchemaService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlTsDatabaseSchemaService.java @@ -16,9 +16,12 @@ package org.thingsboard.server.service.install; import org.springframework.stereotype.Service; +import org.thingsboard.server.dao.util.SqlTsDao; @Service -public class SqlTsDatabaseSchemaService extends SqlAbstractDatabaseSchemaService { +@SqlTsDao +public class SqlTsDatabaseSchemaService extends SqlAbstractDatabaseSchemaService + implements TsDatabaseSchemaService { public SqlTsDatabaseSchemaService() { super("schema-ts.sql"); } diff --git a/application/src/main/java/org/thingsboard/server/service/install/TsDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/TsDatabaseSchemaService.java new file mode 100644 index 0000000000..d95166feb8 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/install/TsDatabaseSchemaService.java @@ -0,0 +1,4 @@ +package org.thingsboard.server.service.install; + +public interface TsDatabaseSchemaService extends DatabaseSchemaService { +} From 5165160b3b618001c4eb3d7a9a1900f84e761c6f Mon Sep 17 00:00:00 2001 From: hagaic Date: Wed, 22 Aug 2018 06:55:29 +0300 Subject: [PATCH 005/118] revert upgrade C* in hybrid mode, since no upgrade of TS tables --- .../service/install/CassandraDatabaseUpgradeService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 2cbd167242..f4ff92cf23 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 @@ -23,7 +23,7 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.dao.cassandra.CassandraCluster; import org.thingsboard.server.dao.cassandra.CassandraInstallCluster; import org.thingsboard.server.dao.dashboard.DashboardService; -import org.thingsboard.server.dao.util.NoSqlAnyDao; +import org.thingsboard.server.dao.util.NoSqlDao; import org.thingsboard.server.service.install.cql.CQLStatementsParser; import org.thingsboard.server.service.install.cql.CassandraDbHelper; @@ -45,7 +45,7 @@ import static org.thingsboard.server.service.install.DatabaseHelper.TENANT_ID; import static org.thingsboard.server.service.install.DatabaseHelper.TITLE; @Service -@NoSqlAnyDao +@NoSqlDao @Profile("install") @Slf4j public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService { From 8f614846eb0f456efdd0f915c4388db0acb8a35c Mon Sep 17 00:00:00 2001 From: hagaic Date: Wed, 22 Aug 2018 09:16:59 +0300 Subject: [PATCH 006/118] add license headers --- .../install/EntityDatabaseSchemaService.java | 15 +++++++++++++++ .../service/install/TsDatabaseSchemaService.java | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/service/install/EntityDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/EntityDatabaseSchemaService.java index 1d0ddc34a4..c215ea0d8f 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/EntityDatabaseSchemaService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/EntityDatabaseSchemaService.java @@ -1,3 +1,18 @@ +/** + * 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.service.install; public interface EntityDatabaseSchemaService extends DatabaseSchemaService { diff --git a/application/src/main/java/org/thingsboard/server/service/install/TsDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/TsDatabaseSchemaService.java index d95166feb8..0a2ba7586c 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/TsDatabaseSchemaService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/TsDatabaseSchemaService.java @@ -1,3 +1,18 @@ +/** + * 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.service.install; public interface TsDatabaseSchemaService extends DatabaseSchemaService { From 2b0ac1f1d031c578b1b0de036dacc0d2588166cb Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 27 Aug 2018 15:16:46 +0300 Subject: [PATCH 007/118] Create EntityViewId class --- .../server/common/data/id/EntityViewId.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/id/EntityViewId.java diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityViewId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityViewId.java new file mode 100644 index 0000000000..2d6a0fbf28 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityViewId.java @@ -0,0 +1,27 @@ +package org.thingsboard.server.common.data.id; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.thingsboard.server.common.data.EntityType; + +import java.util.UUID; + +public class EntityViewId extends UUIDBased implements EntityId { + + + private static final long serialVersionUID = 1L; + + @JsonCreator + public EntityViewId(@JsonProperty("id") UUID id) { + super(id); + } + + public static EntityViewId fromString(String entityViewID) { + return new EntityViewId(UUID.fromString(entityViewID)); + } + + @Override + public EntityType getEntityType() { + return EntityType.ENTITY_VIEW; + } +} From 30e1c480ed6f84c48cc391042d3014ad614e7d5c Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 27 Aug 2018 16:05:53 +0300 Subject: [PATCH 008/118] Was created EntityView class --- .../server/common/data/EntityType.java | 2 +- .../server/common/data/EntityView.java | 127 ++++++++++++++++++ 2 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java index fe9c018718..ef4994adda 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java @@ -19,5 +19,5 @@ package org.thingsboard.server.common.data; * @author Andrew Shvayka */ public enum EntityType { - TENANT, CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, ALARM, RULE_CHAIN, RULE_NODE; + TENANT, CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, ALARM, RULE_CHAIN, RULE_NODE, ENTITY_VIEW } 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 new file mode 100644 index 0000000000..b160b888f5 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java @@ -0,0 +1,127 @@ +package org.thingsboard.server.common.data; + +import lombok.EqualsAndHashCode; +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 java.util.List; + +@EqualsAndHashCode(callSuper = true) +public class EntityView extends SearchTextBasedWithAdditionalInfo + implements HasName, HasTenantId, HasCustomerId { + + private static final long serialVersionUID = 5582010124562018986L; + + private EntityId entityId; + private TenantId tenantId; + private CustomerId customerId; + private String name; + private List keys; + private Long tsStart; + private Long tsEnd; + + public EntityView() { + } + + public EntityView(EntityViewId id) { + super(id); + } + + public EntityView(EntityId entityId, + TenantId tenantId, + CustomerId customerId, + String name, + List keys, + Long tsStart, + Long tsEnd) { + + this.entityId = entityId; + this.tenantId = tenantId; + this.customerId = customerId; + this.name = name; + this.keys = keys; + this.tsStart = tsStart; + this.tsEnd = tsEnd; + } + + public EntityView(EntityView entityView) { + super(entityView); + } + + public EntityId getEntityId() { + return entityId; + } + + public void setEntityId(EntityId entityId) { + this.entityId = entityId; + } + + public void setTenantId(TenantId tenantId) { + this.tenantId = tenantId; + } + + public void setCustomerId(CustomerId customerId) { + this.customerId = customerId; + } + + public void setName(String name) { + this.name = name; + } + + public List getKeys() { + return keys; + } + + public void setKeys(List keys) { + this.keys = keys; + } + + public Long getTsStart() { + return tsStart; + } + + public void setTsStart(Long tsStart) { + this.tsStart = tsStart; + } + + public Long getTsEnd() { + return tsEnd; + } + + public void setTsEnd(Long tsEnd) { + this.tsEnd = tsEnd; + } + + @Override + public String getSearchText() { + return getName() /*What the ...*/; + } + + @Override + public CustomerId getCustomerId() { + return customerId; + } + + @Override + public String getName() { + return name; + } + + @Override + public TenantId getTenantId() { + return tenantId; + } + + @Override + public String toString() { + return "EntityView{entityId=" + entityId.getId() + + ", tenantId=" + tenantId + + ", customerId=" + customerId + + ", name='" + name + "\'" + + ", keys=" + String.join(",", keys) + + ", tsStart=" + tsStart + + ", tsEnd=" + tsEnd + "}"; + } +} From a22bef2e182f3ac21ecd410202d77895328f073c Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 27 Aug 2018 17:01:58 +0300 Subject: [PATCH 009/118] Was created first test to EntityViewController --- .../controller/BaseDeviceControllerTest.java | 4 +- .../BaseEntityViewControllerTest.java | 81 +++++++++++++++++++ .../nosql/EntityViewControllerNoSqlTest.java | 24 ++++++ .../sql/EntityViewControllerSqlTest.java | 26 ++++++ 4 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java create mode 100644 application/src/test/java/org/thingsboard/server/controller/nosql/EntityViewControllerNoSqlTest.java create mode 100644 application/src/test/java/org/thingsboard/server/controller/sql/EntityViewControllerSqlTest.java diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java index 2b86934185..55e18fbeb5 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java @@ -41,7 +41,9 @@ import org.junit.Before; import org.junit.Test; import com.fasterxml.jackson.core.type.TypeReference; - +/** + * Created by Victor Basanets on 8/27/2017. + */ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { private IdComparator idComparator = new IdComparator<>(); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java new file mode 100644 index 0000000000..45b068be19 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -0,0 +1,81 @@ +package org.thingsboard.server.controller; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +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.User; +import org.thingsboard.server.common.data.security.Authority; + +import java.util.Arrays; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; + +public abstract class BaseEntityViewControllerTest extends AbstractControllerTest { + + private Tenant savedTenant; + private User tenantAdmin; + private Device testDevice; + + @Before + public void beforeTest() throws Exception { + loginSysAdmin(); + + Device device = new Device(); + device.setName("Test device"); + device.setType("default"); + testDevice = doPost("/api/device", device, Device.class); + + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + savedTenant = doPost("/api/tenant", tenant, Tenant.class); + + Assert.assertNotNull(savedTenant); + + tenantAdmin = new User(); + tenantAdmin.setAuthority(Authority.TENANT_ADMIN); + tenantAdmin.setTenantId(savedTenant.getId()); + tenantAdmin.setEmail("tenant2@thingsboard.org"); + tenantAdmin.setFirstName("Joe"); + tenantAdmin.setLastName("Downs"); + + tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); + } + + @After + public void afterTest() throws Exception { + loginSysAdmin(); + + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) + .andExpect(status().isOk()); + } + + @Test + public void testSaveEntityViewWithIdOfDevice() throws Exception { + EntityView view = new EntityView(); + view.setEntityId(testDevice.getId()); + view.setName("Test entity view"); + view.setKeys(Arrays.asList("key1", "key2", "key3")); + EntityView savedView = doPost("/api/entity-view", view, EntityView.class); + + Assert.assertNotNull(savedView); + Assert.assertNotNull(savedView.getId()); + Assert.assertTrue(savedView.getCreatedTime() > 0); + Assert.assertEquals(savedTenant.getId(), savedView.getTenantId()); + Assert.assertNotNull(savedView.getCustomerId()); + Assert.assertEquals(NULL_UUID, savedView.getCustomerId().getId()); + Assert.assertEquals(savedView.getName(), savedView.getName()); + + savedView.setName("New test entity view"); + doPost("/api/entity-view", savedView, EntityView.class); + + EntityView foundEntityView = doGet("/api/device/" + + savedView.getId().getId().toString(), EntityView.class); + + Assert.assertEquals(foundEntityView.getName(), savedView.getName()); + } +} 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 new file mode 100644 index 0000000000..bc461a3119 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/controller/nosql/EntityViewControllerNoSqlTest.java @@ -0,0 +1,24 @@ +/** + * 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.controller.nosql; + +import org.thingsboard.server.controller.BaseEntityViewControllerTest; +/** + * Created by Victor Basanets on 8/27/2017. + */ +public class EntityViewControllerNoSqlTest + extends BaseEntityViewControllerTest { +} diff --git a/application/src/test/java/org/thingsboard/server/controller/sql/EntityViewControllerSqlTest.java b/application/src/test/java/org/thingsboard/server/controller/sql/EntityViewControllerSqlTest.java new file mode 100644 index 0000000000..f481ee718e --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/controller/sql/EntityViewControllerSqlTest.java @@ -0,0 +1,26 @@ +/** + * 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.controller.sql; + +import org.thingsboard.server.controller.BaseEntityViewControllerTest; +import org.thingsboard.server.dao.service.DaoSqlTest; +/** + * Created by Victor Basanets on 8/27/2017. + */ +@DaoSqlTest +public class EntityViewControllerSqlTest + extends BaseEntityViewControllerTest { +} From 076bddb32a3224350fa9929e8b6abc5b6c174bd8 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 27 Aug 2018 17:15:01 +0300 Subject: [PATCH 010/118] Was modified thingsboard.yml --- .../src/main/resources/thingsboard.yml | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 743a8607b5..3e05ff7e39 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -343,36 +343,36 @@ spring.resources.chain: enabled: "true" # HSQLDB DAO Configuration -spring: - data: - jpa: - repositories: - enabled: "true" - jpa: - hibernate: - ddl-auto: "validate" - database-platform: "${SPRING_JPA_DATABASE_PLATFORM:org.hibernate.dialect.HSQLDialect}" - datasource: - driverClassName: "${SPRING_DRIVER_CLASS_NAME:org.hsqldb.jdbc.JDBCDriver}" - url: "${SPRING_DATASOURCE_URL:jdbc:hsqldb:file:${SQL_DATA_FOLDER:/tmp}/thingsboardDb;sql.enforce_size=false;hsqldb.log_size=5}" - username: "${SPRING_DATASOURCE_USERNAME:sa}" - password: "${SPRING_DATASOURCE_PASSWORD:}" +# spring: +# data: +# jpa: +# repositories: +# enabled: "true" +# jpa: +# hibernate: +# ddl-auto: "validate" +# database-platform: "${SPRING_JPA_DATABASE_PLATFORM:org.hibernate.dialect.HSQLDialect}" +# datasource: +# driverClassName: "${SPRING_DRIVER_CLASS_NAME:org.hsqldb.jdbc.JDBCDriver}" +# url: "${SPRING_DATASOURCE_URL:jdbc:hsqldb:file:${SQL_DATA_FOLDER:/tmp}/thingsboardDb;sql.enforce_size=false;hsqldb.log_size=5}" +# username: "${SPRING_DATASOURCE_USERNAME:sa}" +# password: "${SPRING_DATASOURCE_PASSWORD:}" # PostgreSQL DAO Configuration -#spring: -# data: -# sql: -# repositories: -# enabled: "true" -# sql: -# hibernate: -# ddl-auto: "validate" -# database-platform: "${SPRING_JPA_DATABASE_PLATFORM:org.hibernate.dialect.PostgreSQLDialect}" -# datasource: -# driverClassName: "${SPRING_DRIVER_CLASS_NAME:org.postgresql.Driver}" -# url: "${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/thingsboard}" -# username: "${SPRING_DATASOURCE_USERNAME:postgres}" -# password: "${SPRING_DATASOURCE_PASSWORD:postgres}" +spring: + data: + sql: + repositories: + enabled: "true" + sql: + hibernate: + ddl-auto: "validate" + database-platform: "${SPRING_JPA_DATABASE_PLATFORM:org.hibernate.dialect.PostgreSQLDialect}" + datasource: + driverClassName: "${SPRING_DRIVER_CLASS_NAME:org.postgresql.Driver}" + url: "${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/thingsboard}" + username: "${SPRING_DATASOURCE_USERNAME:postgres}" + password: "${SPRING_DATASOURCE_PASSWORD:postgres}" # Audit log parameters audit_log: From 09a13ba82d5a86c318582e12e867d3d7ee052175 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 27 Aug 2018 17:30:49 +0300 Subject: [PATCH 011/118] Was added descriptive headings titles to source code files --- .../BaseEntityViewControllerTest.java | 18 ++++++++++++++++++ .../nosql/EntityViewControllerNoSqlTest.java | 1 + .../sql/EntityViewControllerSqlTest.java | 1 + .../server/common/data/EntityView.java | 18 ++++++++++++++++++ .../server/common/data/id/EntityViewId.java | 19 ++++++++++++++++++- 5 files changed, 56 insertions(+), 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index 45b068be19..e87ea6b4ea 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -1,3 +1,18 @@ +/** + * 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.controller; import org.junit.After; @@ -15,6 +30,9 @@ import java.util.Arrays; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; +/** + * Created by Victor Basanets on 8/27/2017. + */ public abstract class BaseEntityViewControllerTest extends AbstractControllerTest { private Tenant savedTenant; 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 bc461a3119..095edd19f8 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,6 +16,7 @@ package org.thingsboard.server.controller.nosql; import org.thingsboard.server.controller.BaseEntityViewControllerTest; + /** * Created by Victor Basanets on 8/27/2017. */ diff --git a/application/src/test/java/org/thingsboard/server/controller/sql/EntityViewControllerSqlTest.java b/application/src/test/java/org/thingsboard/server/controller/sql/EntityViewControllerSqlTest.java index f481ee718e..84e621fcf6 100644 --- a/application/src/test/java/org/thingsboard/server/controller/sql/EntityViewControllerSqlTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/sql/EntityViewControllerSqlTest.java @@ -17,6 +17,7 @@ package org.thingsboard.server.controller.sql; import org.thingsboard.server.controller.BaseEntityViewControllerTest; import org.thingsboard.server.dao.service.DaoSqlTest; + /** * Created by Victor Basanets on 8/27/2017. */ 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 b160b888f5..06debfb001 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 @@ -1,3 +1,18 @@ +/** + * 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.common.data; import lombok.EqualsAndHashCode; @@ -8,6 +23,9 @@ import org.thingsboard.server.common.data.id.TenantId; import java.util.List; +/** + * Created by Victor Basanets on 8/27/2017. + */ @EqualsAndHashCode(callSuper = true) public class EntityView extends SearchTextBasedWithAdditionalInfo implements HasName, HasTenantId, HasCustomerId { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityViewId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityViewId.java index 2d6a0fbf28..459dd990a4 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityViewId.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityViewId.java @@ -1,3 +1,18 @@ +/** + * 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.common.data.id; import com.fasterxml.jackson.annotation.JsonCreator; @@ -6,9 +21,11 @@ import org.thingsboard.server.common.data.EntityType; import java.util.UUID; +/** + * Created by Victor Basanets on 8/27/2017. + */ public class EntityViewId extends UUIDBased implements EntityId { - private static final long serialVersionUID = 1L; @JsonCreator From 1120f0a4c5881c9d74530ea02b26a18ed3240ff3 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 27 Aug 2018 18:39:22 +0300 Subject: [PATCH 012/118] Was added EntityViewSevice interface --- .../dao/entityview/EntityViewService.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java 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 new file mode 100644 index 0000000000..f4e1700bb3 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java @@ -0,0 +1,31 @@ +package org.thingsboard.server.dao.entityview; + +import org.thingsboard.server.common.data.EntityView; +import org.thingsboard.server.common.data.id.CustomerId; +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; + +public interface EntityViewService { + EntityView findEntityViewById(EntityViewId entityViewId); + + + EntityView findEntityViewByTenantIdAndName(TenantId tenantId, String name); + + EntityView saveEntityView(EntityView entityView); + + EntityView assignEntityViewToCustomer(EntityViewId entityViewId, CustomerId customerId); + + void deleteEntityView(EntityViewId entityViewId); + + TextPageData findEntityViewByTenantId(TenantId tenantId, TextPageLink pageLink); + + TextPageData findEntityViewByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink); + + void deleteEntityViewByTenantId(TenantId tenantId); + + TextPageData findEntityViewByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink); + + TextPageData findEntityViewByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, TextPageLink pageLink); +} From 7e00615a0d017e77695e5b0385d4dcab0345bba5 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 27 Aug 2018 19:03:39 +0300 Subject: [PATCH 013/118] Was modified BaseController abstract class: added EntityViewService --- .../server/controller/BaseController.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index de73fe0796..af62e04cff 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -56,6 +56,7 @@ import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.model.ModelConstants; @@ -139,6 +140,9 @@ public abstract class BaseController { @Autowired protected DeviceStateService deviceStateService; + @Autowired + protected EntityViewService entityViewService; + @ExceptionHandler(ThingsboardException.class) public void handleThingsboardException(ThingsboardException ex, HttpServletResponse response) { errorResponseHandler.handle(ex, response); @@ -313,6 +317,9 @@ public abstract class BaseController { case USER: checkUserId(new UserId(entityId.getId())); return; + case ENTITY_VIEW: + checkEntityView(entityViewService.findEntityViewById(new EntityViewId(entityId.getId()))); + return; default: throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType()); } @@ -340,6 +347,25 @@ public abstract class BaseController { } } + protected EntityView checkEntityViewId(EntityViewId entityViewId) throws ThingsboardException { + try { + validateId(entityViewId, "Incorrect entityViewId " + entityViewId); + EntityView entityView = entityViewService.findEntityViewById(entityViewId); + checkEntityView(entityView); + return entityView; + } catch (Exception e) { + throw handleException(e, false); + } + } + + protected void checkEntityView(EntityView entityView) throws ThingsboardException { + checkNotNull(entityView); + checkTenantId(entityView.getTenantId()); + if (entityView.getCustomerId() != null && !entityView.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { + checkCustomerId(entityView.getCustomerId()); + } + } + Asset checkAssetId(AssetId assetId) throws ThingsboardException { try { validateId(assetId, "Incorrect assetId " + assetId); From 9bcfec00ba95bd481a88fa92ee5fee9e8e159576 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Tue, 28 Aug 2018 13:57:42 +0300 Subject: [PATCH 014/118] Was created controller EntityViewController --- .../controller/EntityViewController.java | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 application/src/main/java/org/thingsboard/server/controller/EntityViewController.java diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java new file mode 100644 index 0000000000..acb583b396 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java @@ -0,0 +1,78 @@ +/** + * 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.controller; + +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.EntityView; +import org.thingsboard.server.common.data.audit.ActionType; +import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.EntityViewId; + +/** + * Created by Victor Basanets on 8/28/2017. + */ +@RestController +@RequestMapping("/api") +public class EntityViewController extends BaseController { + + public static final String ENTITY_VIEW_ID = "entityViewId"; + + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/entity-view/{entityViewId}", method = RequestMethod.GET) + @ResponseBody + public EntityView getEntityViewById(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) + throws ThingsboardException { + + checkParameter(ENTITY_VIEW_ID, strEntityViewId); + try { + EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); + return checkEntityViewId(entityViewId); + } catch (Exception e) { + throw handleException(e); + } + } + + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/entity-view", method = RequestMethod.POST) + @ResponseBody + public EntityView saveEntityView(@RequestBody EntityView entityView) + throws ThingsboardException { + + try { + entityView.setTenantId(getCurrentUser().getTenantId()); + EntityView savedEntityView = checkNotNull(entityViewService.saveEntityView(entityView)); + + logEntityAction(savedEntityView.getId(), savedEntityView, null, + entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); + + return savedEntityView; + + } catch (Exception e) { + + logEntityAction(emptyId(EntityType.ENTITY_VIEW), entityView, null, + entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e); + + throw handleException(e); + } + } +} From 14f658c92a166e9747942f0eb199dd123cf781c4 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 29 Aug 2018 10:48:11 +0300 Subject: [PATCH 015/118] Was created EntityViewService interface --- .../dao/entityview/EntityViewService.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) 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 f4e1700bb3..9077a29a1c 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 @@ -1,3 +1,18 @@ +/** + * 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 org.thingsboard.server.common.data.EntityView; @@ -7,9 +22,12 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; +/** + * Created by Victor Basanets on 8/27/2017. + */ public interface EntityViewService { - EntityView findEntityViewById(EntityViewId entityViewId); + EntityView findEntityViewById(EntityViewId entityViewId); EntityView findEntityViewByTenantIdAndName(TenantId tenantId, String name); From e55a0d3fd6384845fdd81f52e554045293d6f05a Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 29 Aug 2018 10:57:00 +0300 Subject: [PATCH 016/118] Was modified constructor of EntityView class --- .../main/java/org/thingsboard/server/common/data/EntityView.java | 1 + 1 file changed, 1 insertion(+) 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 06debfb001..6b4dcd1a0c 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 @@ -41,6 +41,7 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo private Long tsEnd; public EntityView() { + super(); } public EntityView(EntityViewId id) { From f5200b3b15d8b636c8eb1fc53d943c7b4041ac19 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 29 Aug 2018 12:25:42 +0300 Subject: [PATCH 017/118] Was added the constant 'ENTITY_VIEW_CACHE' --- .../java/org/thingsboard/server/common/data/CacheConstants.java | 1 + 1 file changed, 1 insertion(+) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java b/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java index 21de402721..698a69ef6b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java @@ -20,4 +20,5 @@ public class CacheConstants { public static final String RELATIONS_CACHE = "relations"; public static final String DEVICE_CACHE = "devices"; public static final String ASSET_CACHE = "assets"; + public static final String ENTITY_VIEW_CACHE = "entityViews"; } From e6580ca1af296a644195f5a7133a0e9c491550b1 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 29 Aug 2018 12:31:37 +0300 Subject: [PATCH 018/118] Was added new abstract methods --- .../server/dao/entityview/EntityViewService.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) 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 9077a29a1c..8fcaf30dff 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 @@ -35,6 +35,8 @@ public interface EntityViewService { EntityView assignEntityViewToCustomer(EntityViewId entityViewId, CustomerId customerId); + EntityView unassignEntityViewFromCustomer(EntityViewId entityViewId); + void deleteEntityView(EntityViewId entityViewId); TextPageData findEntityViewByTenantId(TenantId tenantId, TextPageLink pageLink); @@ -43,7 +45,11 @@ public interface EntityViewService { void deleteEntityViewByTenantId(TenantId tenantId); - TextPageData findEntityViewByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink); + TextPageData findEntityViewsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, + TextPageLink pageLink); + + TextPageData findEntityViewsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, + String type, TextPageLink pageLink); - TextPageData findEntityViewByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, TextPageLink pageLink); + void unassignCustomerEntityViews(TenantId tenantId, CustomerId customerId); } From 7c5d595dbe795e910ea1edf87e66dc0f2c39420c Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 29 Aug 2018 12:33:17 +0300 Subject: [PATCH 019/118] Was created implementation of EntityViewService interface --- .../dao/entityview/EntityViewServiceImpl.java | 281 ++++++++++++++++++ 1 file changed, 281 insertions(+) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java 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 new file mode 100644 index 0000000000..952b1fd46b --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -0,0 +1,281 @@ +/** + * 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 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.stereotype.Service; +import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.EntityView; +import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.id.CustomerId; +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.dao.customer.CustomerDao; +import org.thingsboard.server.dao.entity.AbstractEntityService; +import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.service.DataValidator; +import org.thingsboard.server.dao.service.PaginatedRemover; +import org.thingsboard.server.dao.tenant.TenantDao; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +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; +import static org.thingsboard.server.dao.service.Validator.validateString; + +/** + * Created by Victor Basanets on 8/28/2017. + */ +@Service +@Slf4j +public class EntityViewServiceImpl extends AbstractEntityService + implements EntityViewService { + + public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; + public static final String INCORRECT_PAGE_LINK = "Incorrect page link "; + public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId "; + public static final String INCORRECT_ENTITY_VIEW_ID = "Incorrect entityViewId "; + + @Autowired + private EntityViewDao entityViewDao; + + @Autowired + private TenantDao tenantDao; + + @Autowired + private CustomerDao customerDao; + + @Autowired + private CacheManager cacheManager; + + @Override + public EntityView findEntityViewById(EntityViewId entityViewId) { + log.trace("Executing findEntityViewById [{}]", entityViewId); + validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); + return entityViewDao.findById(entityViewId.getId()); + } + + @Override + public EntityView findEntityViewByTenantIdAndName(TenantId tenantId, String name) { + log.trace("Executing findEntityViewByTenantIdAndName [{}][{}]", tenantId, name); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + return entityViewDao.findEntityViewByTenantIdAndName(tenantId.getId(), name) + .orElse(null); + } + + @Override + public EntityView saveEntityView(EntityView entityView) { + log.trace("Executing save entity view [{}]", entityView); + entityViewValidator.validate(entityView); + return entityViewDao.save(entityView); + } + + @Override + public EntityView assignEntityViewToCustomer(EntityViewId entityViewId, CustomerId customerId) { + EntityView entityView = findEntityViewById(entityViewId); + entityView.setCustomerId(customerId); + return saveEntityView(entityView); + } + + @Override + public EntityView unassignEntityViewFromCustomer(EntityViewId entityViewId) { + EntityView entityView = findEntityViewById(entityViewId); + entityView.setCustomerId(null); + return saveEntityView(entityView); + } + + @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 list = new ArrayList<>(); + list.add(entityView.getTenantId()); + list.add(entityView.getName()); + cache.evict(list); + entityViewDao.removeById(entityViewId.getId()); + } + + @Override + public TextPageData findEntityViewByTenantId(TenantId tenantId, TextPageLink pageLink) { + log.trace("Executing findEntityViewByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); + List entityViews = entityViewDao.findEntityViewByTenantId(tenantId.getId(), pageLink); + return new TextPageData<>(entityViews, pageLink); + } + + @Override + public TextPageData findEntityViewByTenantIdAndType(TenantId tenantId, String type, + TextPageLink pageLink) { + + log.trace("Executing findEntityViewByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", + tenantId, type, pageLink); + + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateString(type, "Incorrect type " + type); + validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); + List entityViews = entityViewDao.findEntityViewByTenantIdAndType(tenantId.getId(), + type, pageLink); + + return new TextPageData<>(entityViews, pageLink); + } + + @Override + public void deleteEntityViewByTenantId(TenantId tenantId) { + log.trace("Executing deleteEntityViewByTenantId, tenantId [{}]", tenantId); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + tenantEntityViewRemover.removeEntities(tenantId); + } + + @Override + public TextPageData findEntityViewsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, + TextPageLink pageLink) { + + log.trace("Executing findEntityViewByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", + tenantId, customerId, pageLink); + + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); + validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); + List entityViews = entityViewDao.findEntityViewsByTenantIdAndCustomerId(tenantId.getId(), + customerId.getId(), pageLink); + + return new TextPageData<>(entityViews, pageLink); + } + + @Override + public TextPageData findEntityViewsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, + String type, TextPageLink pageLink) { + + log.trace("Executing findEntityViewsByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}], type [{}]," + + " pageLink [{}]", tenantId, customerId, type, pageLink); + + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); + validateString(type, "Incorrect type " + type); + validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); + List entityViews = entityViewDao.findEntityViewsByTenantIdAndCustomerIdAndType(tenantId.getId(), + customerId.getId(), type, pageLink); + + return new TextPageData<>(entityViews, pageLink); + } + + @Override + public void unassignCustomerEntityViews(TenantId tenantId, CustomerId customerId) { + log.trace("Executing unassignCustomerEntityViews, tenantId [{}], customerId [{}]", tenantId, customerId); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); + new CustomerEntityViewsUnAssigner(tenantId).removeEntities(customerId); + } + + private DataValidator entityViewValidator = + new DataValidator() { + + @Override + protected void validateCreate(EntityView entityView) { + entityViewDao.findEntityViewByTenantIdAndName(entityView.getTenantId().getId(), entityView.getName()) + .ifPresent( e -> { + throw new DataValidationException("Entity view with such name already exists!"); + }); + } + + @Override + protected void validateUpdate(EntityView entityView) { + entityViewDao.findEntityViewByTenantIdAndName(entityView.getTenantId().getId(), entityView.getName()) + .ifPresent( e -> { + if (!e.getUuidId().equals(entityView.getUuidId())) { + throw new DataValidationException("Entity view with such name already exists!"); + } + }); + } + + @Override + protected void validateDataImpl(EntityView entityView) { + if (StringUtils.isEmpty(String.join("", entityView.getKeys()))) { + throw new DataValidationException("Entity view type should be specified!"); + } + if (StringUtils.isEmpty(entityView.getName())) { + throw new DataValidationException("Entity view name should be specified!"); + } + if (entityView.getTenantId() == null) { + throw new DataValidationException("Entity view should be assigned to tenant!"); + } else { + Tenant tenant = tenantDao.findById(entityView.getTenantId().getId()); + if (tenant == null) { + throw new DataValidationException("Entity view is referencing to non-existent tenant!"); + } + } + if (entityView.getCustomerId() == null) { + entityView.setCustomerId(new CustomerId(NULL_UUID)); + } else if (!entityView.getCustomerId().getId().equals(NULL_UUID)) { + Customer customer = customerDao.findById(entityView.getCustomerId().getId()); + if (customer == null) { + throw new DataValidationException("Can't assign entity view to non-existent customer!"); + } + if (!customer.getTenantId().getId().equals(entityView.getTenantId().getId())) { + throw new DataValidationException("Can't assign entity view to customer from different tenant!"); + } + } + } + }; + + private PaginatedRemover tenantEntityViewRemover = + new PaginatedRemover() { + + @Override + protected List findEntities(TenantId id, TextPageLink pageLink) { + return entityViewDao.findEntityViewByTenantId(id.getId(), pageLink); + } + + @Override + protected void removeEntity(EntityView entity) { + deleteEntityView(new EntityViewId(entity.getUuidId())); + } + }; + + private class CustomerEntityViewsUnAssigner extends PaginatedRemover { + + private TenantId tenantId; + + CustomerEntityViewsUnAssigner(TenantId tenantId) { + this.tenantId = tenantId; + } + + @Override + protected List findEntities(CustomerId id, TextPageLink pageLink) { + return entityViewDao.findEntityViewsByTenantIdAndCustomerId(tenantId.getId(), id.getId(), pageLink); + } + + @Override + protected void removeEntity(EntityView entity) { + unassignEntityViewFromCustomer(new EntityViewId(entity.getUuidId())); + } + + } +} From 17866a979868d1252052916ed1c934fcc4735ee6 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 29 Aug 2018 12:34:00 +0300 Subject: [PATCH 020/118] Was created dao interface --- .../server/dao/entityview/EntityViewDao.java | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java 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 new file mode 100644 index 0000000000..fbd1957db8 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java @@ -0,0 +1,81 @@ +/** + * 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 org.thingsboard.server.common.data.EntityView; +import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.dao.Dao; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +/** + * Created by Victor Basanets on 8/28/2017. + */ +public interface EntityViewDao extends Dao { + + /** + * Find entity views by tenantId and page link. + * + * @param tenantId the tenantId + * @param pageLink the page link + * @return the list of entity view objects + */ + List findEntityViewByTenantId(UUID tenantId, TextPageLink pageLink); + + /** + * Find entity views by tenantId and entity view name. + * + * @param tenantId the tenantId + * @param name the entity view name + * @return the optional entity view object + */ + Optional findEntityViewByTenantIdAndName(UUID tenantId, String name); + + /** + * Find entity views by tenantId, type and page link. + * + * @param tenantId the tenantId + * @param type the type + * @param pageLink the page link + * @return the list of entity view objects + */ + List findEntityViewByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink); + + /** + * Find entity views by tenantId, customerId and page link. + * + * @param tenantId the tenantId + * @param customerId the customerId + * @param pageLink the page link + * @return the list of entity view objects + */ + List findEntityViewsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink); + + /** + * Find entity views by tenantId, customerId, type and page link. + * + * @param tenantId the tenantId + * @param customerId the customerId + * @param type the type + * @param pageLink the page link + * @return the list of entity view objects + */ + List findEntityViewsByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, + TextPageLink pageLink); + +} From f880fc2e429113a080eeab1bc54dea609f102739 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 29 Aug 2018 13:26:00 +0300 Subject: [PATCH 021/118] Was added method for delete of entity view --- .../controller/EntityViewController.java | 42 ++++++++++++++----- 1 file changed, 31 insertions(+), 11 deletions(-) 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 acb583b396..fd3ccf2fe1 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java @@ -15,18 +15,21 @@ */ package org.thingsboard.server.controller; +import com.google.common.util.concurrent.ListenableFuture; +import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityViewId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.service.security.model.SecurityUser; + +import java.util.ArrayList; +import java.util.List; /** * Created by Victor Basanets on 8/28/2017. @@ -55,24 +58,41 @@ public class EntityViewController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/entity-view", method = RequestMethod.POST) @ResponseBody - public EntityView saveEntityView(@RequestBody EntityView entityView) - throws ThingsboardException { - + public EntityView saveEntityView(@RequestBody EntityView entityView) throws ThingsboardException { try { entityView.setTenantId(getCurrentUser().getTenantId()); EntityView savedEntityView = checkNotNull(entityViewService.saveEntityView(entityView)); - logEntityAction(savedEntityView.getId(), savedEntityView, null, entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); return savedEntityView; } catch (Exception e) { - logEntityAction(emptyId(EntityType.ENTITY_VIEW), entityView, null, entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e); throw handleException(e); } } + + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/entity-view/{entityViewId}", method = RequestMethod.DELETE) + @ResponseStatus(value = HttpStatus.OK) + public void deleteEntityView(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { + checkParameter(ENTITY_VIEW_ID, strEntityViewId); + try { + EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); + EntityView entityView = checkEntityViewId(entityViewId); + entityViewService.deleteEntityView(entityViewId); + + logEntityAction(entityViewId, entityView, entityView.getCustomerId(), + ActionType.DELETED,null, strEntityViewId); + } catch (Exception e) { + logEntityAction(emptyId(EntityType.ENTITY_VIEW), + null, + null, + ActionType.DELETED, e, strEntityViewId); + throw handleException(e); + } + } } From c8733b695c999102acd707bf46e98f2a97b515b5 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 29 Aug 2018 13:48:26 +0300 Subject: [PATCH 022/118] Was added tests of find entity by id and delete entity methods --- .../BaseEntityViewControllerTest.java | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index e87ea6b4ea..d0598586d7 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -72,11 +72,24 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes .andExpect(status().isOk()); } + @Test + public void testFindEntityViewById() throws Exception { + EntityView view = new EntityView(); + view.setName("Test entity view"); + view.setEntityId(testDevice.getId()); + view.setKeys(Arrays.asList("key1", "key2", "key3")); + EntityView savedView = doPost("/api/entity-view", view, EntityView.class); + EntityView foundView = doGet("/api/entity-view/" + savedView.getId().getId().toString(), EntityView.class); + Assert.assertNotNull(foundView); + Assert.assertEquals(savedView, foundView); + } + @Test public void testSaveEntityViewWithIdOfDevice() throws Exception { EntityView view = new EntityView(); view.setEntityId(testDevice.getId()); view.setName("Test entity view"); + view.setTenantId(savedTenant.getId()); view.setKeys(Arrays.asList("key1", "key2", "key3")); EntityView savedView = doPost("/api/entity-view", view, EntityView.class); @@ -91,9 +104,24 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes savedView.setName("New test entity view"); doPost("/api/entity-view", savedView, EntityView.class); - EntityView foundEntityView = doGet("/api/device/" + EntityView foundEntityView = doGet("/api/entity-view/" + savedView.getId().getId().toString(), EntityView.class); Assert.assertEquals(foundEntityView.getName(), savedView.getName()); } + + @Test + public void testDeleteEntityView() throws Exception { + EntityView view = new EntityView(); + view.setName("Test entity view"); + view.setEntityId(testDevice.getId()); + view.setKeys(Arrays.asList("key1", "key2", "key3")); + EntityView savedView = doPost("/api/entity-view", view, EntityView.class); + + doDelete("/api/entity-view/" + savedView.getId().getId().toString()) + .andExpect(status().isOk()); + + doGet("/api/entity-view/" + savedView.getId().getId().toString()) + .andExpect(status().isNotFound()); + } } From 6e5bda589f05b5bbe59203423df7bbbe25602510 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 29 Aug 2018 15:28:48 +0300 Subject: [PATCH 023/118] Was returned to the original state --- .../src/main/resources/thingsboard.yml | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 3e05ff7e39..be5149dcb8 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -343,36 +343,36 @@ spring.resources.chain: enabled: "true" # HSQLDB DAO Configuration -# spring: -# data: -# jpa: -# repositories: -# enabled: "true" -# jpa: -# hibernate: -# ddl-auto: "validate" -# database-platform: "${SPRING_JPA_DATABASE_PLATFORM:org.hibernate.dialect.HSQLDialect}" -# datasource: -# driverClassName: "${SPRING_DRIVER_CLASS_NAME:org.hsqldb.jdbc.JDBCDriver}" -# url: "${SPRING_DATASOURCE_URL:jdbc:hsqldb:file:${SQL_DATA_FOLDER:/tmp}/thingsboardDb;sql.enforce_size=false;hsqldb.log_size=5}" -# username: "${SPRING_DATASOURCE_USERNAME:sa}" -# password: "${SPRING_DATASOURCE_PASSWORD:}" +spring: + data: + jpa: + repositories: + enabled: "true" + jpa: + hibernate: + ddl-auto: "validate" + database-platform: "${SPRING_JPA_DATABASE_PLATFORM:org.hibernate.dialect.HSQLDialect}" + datasource: + driverClassName: "${SPRING_DRIVER_CLASS_NAME:org.hsqldb.jdbc.JDBCDriver}" + url: "${SPRING_DATASOURCE_URL:jdbc:hsqldb:file:${SQL_DATA_FOLDER:/tmp}/thingsboardDb;sql.enforce_size=false;hsqldb.log_size=5}" + username: "${SPRING_DATASOURCE_USERNAME:sa}" + password: "${SPRING_DATASOURCE_PASSWORD:}" # PostgreSQL DAO Configuration -spring: - data: - sql: - repositories: - enabled: "true" - sql: - hibernate: - ddl-auto: "validate" - database-platform: "${SPRING_JPA_DATABASE_PLATFORM:org.hibernate.dialect.PostgreSQLDialect}" - datasource: - driverClassName: "${SPRING_DRIVER_CLASS_NAME:org.postgresql.Driver}" - url: "${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/thingsboard}" - username: "${SPRING_DATASOURCE_USERNAME:postgres}" - password: "${SPRING_DATASOURCE_PASSWORD:postgres}" +# spring: +# data: +# sql: +# repositories: +# enabled: "true" +# sql: +# hibernate: +# ddl-auto: "validate" +# database-platform: "${SPRING_JPA_DATABASE_PLATFORM:org.hibernate.dialect.PostgreSQLDialect}" +# datasource: +# driverClassName: "${SPRING_DRIVER_CLASS_NAME:org.postgresql.Driver}" +# url: "${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/thingsboard}" +# username: "${SPRING_DATASOURCE_USERNAME:postgres}" +# password: "${SPRING_DATASOURCE_PASSWORD:postgres}" # Audit log parameters audit_log: From d4cc05deba317714d8481afdd1a789414199d215 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 29 Aug 2018 15:35:10 +0300 Subject: [PATCH 024/118] Was corrected header --- .../server/controller/BaseDeviceControllerTest.java | 4 +--- .../server/controller/BaseEntityViewControllerTest.java | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java index 55e18fbeb5..2b86934185 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java @@ -41,9 +41,7 @@ import org.junit.Before; import org.junit.Test; import com.fasterxml.jackson.core.type.TypeReference; -/** - * Created by Victor Basanets on 8/27/2017. - */ + public abstract class BaseDeviceControllerTest extends AbstractControllerTest { private IdComparator idComparator = new IdComparator<>(); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index d0598586d7..7d9bae1901 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -30,9 +30,6 @@ import java.util.Arrays; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; -/** - * Created by Victor Basanets on 8/27/2017. - */ public abstract class BaseEntityViewControllerTest extends AbstractControllerTest { private Tenant savedTenant; From a11592641c0db367230e451305171930175478dc Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 29 Aug 2018 15:38:02 +0300 Subject: [PATCH 025/118] Were replace constructor, gets & sets by annotations --- .../server/common/data/EntityView.java | 77 ++----------------- 1 file changed, 5 insertions(+), 72 deletions(-) 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 6b4dcd1a0c..b12e38e6b8 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 @@ -15,17 +15,22 @@ */ package org.thingsboard.server.common.data; +import lombok.AllArgsConstructor; +import lombok.Data; import lombok.EqualsAndHashCode; 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 java.beans.ConstructorProperties; import java.util.List; /** * Created by Victor Basanets on 8/27/2017. */ +@Data +@AllArgsConstructor @EqualsAndHashCode(callSuper = true) public class EntityView extends SearchTextBasedWithAdditionalInfo implements HasName, HasTenantId, HasCustomerId { @@ -48,71 +53,10 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo super(id); } - public EntityView(EntityId entityId, - TenantId tenantId, - CustomerId customerId, - String name, - List keys, - Long tsStart, - Long tsEnd) { - - this.entityId = entityId; - this.tenantId = tenantId; - this.customerId = customerId; - this.name = name; - this.keys = keys; - this.tsStart = tsStart; - this.tsEnd = tsEnd; - } - public EntityView(EntityView entityView) { super(entityView); } - public EntityId getEntityId() { - return entityId; - } - - public void setEntityId(EntityId entityId) { - this.entityId = entityId; - } - - public void setTenantId(TenantId tenantId) { - this.tenantId = tenantId; - } - - public void setCustomerId(CustomerId customerId) { - this.customerId = customerId; - } - - public void setName(String name) { - this.name = name; - } - - public List getKeys() { - return keys; - } - - public void setKeys(List keys) { - this.keys = keys; - } - - public Long getTsStart() { - return tsStart; - } - - public void setTsStart(Long tsStart) { - this.tsStart = tsStart; - } - - public Long getTsEnd() { - return tsEnd; - } - - public void setTsEnd(Long tsEnd) { - this.tsEnd = tsEnd; - } - @Override public String getSearchText() { return getName() /*What the ...*/; @@ -132,15 +76,4 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo public TenantId getTenantId() { return tenantId; } - - @Override - public String toString() { - return "EntityView{entityId=" + entityId.getId() + - ", tenantId=" + tenantId + - ", customerId=" + customerId + - ", name='" + name + "\'" + - ", keys=" + String.join(",", keys) + - ", tsStart=" + tsStart + - ", tsEnd=" + tsEnd + "}"; - } } From a1aa321831fe1ae9a6fa4470602e0e6027902298 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 29 Aug 2018 15:39:13 +0300 Subject: [PATCH 026/118] Was deleted Cache --- .../server/dao/entityview/EntityViewServiceImpl.java | 7 ------- 1 file changed, 7 deletions(-) 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 952b1fd46b..d7e9e9a192 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 @@ -38,9 +38,7 @@ import org.thingsboard.server.dao.tenant.TenantDao; import java.util.ArrayList; import java.util.List; -import java.util.Optional; -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; @@ -68,9 +66,6 @@ public class EntityViewServiceImpl extends AbstractEntityService @Autowired private CustomerDao customerDao; - @Autowired - private CacheManager cacheManager; - @Override public EntityView findEntityViewById(EntityViewId entityViewId) { log.trace("Executing findEntityViewById [{}]", entityViewId); @@ -110,14 +105,12 @@ 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 list = new ArrayList<>(); list.add(entityView.getTenantId()); list.add(entityView.getName()); - cache.evict(list); entityViewDao.removeById(entityViewId.getId()); } From 20e63b94889c27c534e2d717b3fd59ecf0d374a3 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Thu, 30 Aug 2018 19:04:35 +0300 Subject: [PATCH 027/118] Was added the model EntityViewEntity constants --- .../server/dao/model/ModelConstants.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) 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 3a934eb5d2..90ccb66ca0 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 @@ -45,6 +45,7 @@ public class ModelConstants { public static final String SEARCH_TEXT_PROPERTY = "search_text"; public static final String ADDITIONAL_INFO_PROPERTY = "additional_info"; public static final String ENTITY_TYPE_PROPERTY = "entity_type"; + /*public static final String ENTITY_VIEW_ID_PROPERTY = "entity_view_id";*/ public static final String ENTITY_TYPE_COLUMN = ENTITY_TYPE_PROPERTY; public static final String ENTITY_ID_COLUMN = "entity_id"; @@ -143,6 +144,19 @@ public class ModelConstants { public static final String DEVICE_BY_TENANT_AND_NAME_VIEW_NAME = "device_by_tenant_and_name"; public static final String DEVICE_TYPES_BY_TENANT_VIEW_NAME = "device_types_by_tenant"; + /** + * Cassandra entityView constants. + */ + public static final String ENTITY_VIEW_TABLE_FAMILY_NAME = "entity_view"; + public static final String ENTITY_VIEW_ENTITY_ID_PROPERTY = ENTITY_ID_COLUMN; + 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_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; + /** * Cassandra audit log constants. */ From ab2a5cceba8969f73a216818045a2374556483cb Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Thu, 30 Aug 2018 19:07:03 +0300 Subject: [PATCH 028/118] Was created new model --- .../dao/model/sql/EntityViewEntity.java | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityViewEntity.java 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 new file mode 100644 index 0000000000..1444e9745e --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityViewEntity.java @@ -0,0 +1,138 @@ +/** + * 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.model.sql; + +import com.datastax.driver.core.utils.UUIDs; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.hibernate.annotations.Type; +import org.hibernate.annotations.TypeDef; +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.dao.model.BaseSqlEntity; +import org.thingsboard.server.dao.model.ModelConstants; +import org.thingsboard.server.dao.model.SearchTextEntity; +import org.thingsboard.server.dao.util.mapping.JsonStringType; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +@Data +@EqualsAndHashCode(callSuper = true) +@Entity +@TypeDef(name = "json", typeClass = JsonStringType.class) +@Table(name = ModelConstants.ENTITY_VIEW_TABLE_FAMILY_NAME) +public class EntityViewEntity extends BaseSqlEntity implements SearchTextEntity { + + @Column(name = ModelConstants.ENTITY_VIEW_ENTITY_ID_PROPERTY) + private String entityId; + + @Column(name = ModelConstants.ENTITY_VIEW_TENANT_ID_PROPERTY) + private String tenantId; + + @Column(name = ModelConstants.ENTITY_VIEW_CUSTOMER_ID_PROPERTY) + private String customerId; + + @Column(name = ModelConstants.ENTITY_VIEW_NAME_PROPERTY) + private String name; + + @Type(type = "json") + @Column(name = ModelConstants.ENTITY_VIEW_KEYS_PROPERTY) + private JsonNode keys; + + @Column(name = ModelConstants.ENTITY_VIEW_TS_BEGIN_PROPERTY) + private String tsBegin; + + @Column(name = ModelConstants.ENTITY_VIEW_TS_END_PROPERTY) + private String tsEnd; + + @Column(name = ModelConstants.SEARCH_TEXT_PROPERTY) + private String searchText; + + @Type(type = "json") + @Column(name = ModelConstants.ENTITY_VIEW_ADDITIONAL_INFO_PROPERTY) + private JsonNode additionalInfo; + + public EntityViewEntity() { + super(); + } + + public EntityViewEntity(EntityView entityView) { + if (entityView.getId() != null) { + this.setId(entityView.getId().getId()); + } + if (entityView.getEntityId() != null) { + this.entityId = toString(entityView.getEntityId().getId()); + } + if (entityView.getTenantId() != null) { + this.tenantId = toString(entityView.getTenantId().getId()); + } + if (entityView.getCustomerId() != null) { + this.customerId = toString(entityView.getCustomerId().getId()); + } + this.name = entityView.getName(); + try { + this.keys = new ObjectMapper().readTree("{\"" + entityView.getName() + "\" : [" + + entityView.getKeys().stream() + .map(k -> "\"" + k + "\"") + .collect(Collectors.joining(", ")) + "]}"); + } catch (IOException e) { + e.printStackTrace(); + } + this.tsBegin = String.valueOf(entityView.getTsBegin()); + this.tsEnd = String.valueOf(entityView.getTsEnd()); + this.additionalInfo = entityView.getAdditionalInfo(); + } + + @Override + public String getSearchTextSource() { + return name; + } + + @Override + public void setSearchText(String searchText) { + this.searchText = searchText; + } + + @Override + public EntityView toData() { + EntityView entityView = new EntityView(new EntityViewId(getId())); + entityView.setCreatedTime(UUIDs.unixTimestamp(getId())); + + /*Ned to refactor and replace DeviceId to Class<> instance*/ + entityView.setEntityId(entityId != null ? new DeviceId(toUUID(entityId)) : null); + entityView.setTenantId(tenantId != null ? new TenantId(toUUID(tenantId)) : null); + entityView.setCustomerId(customerId != null ? new CustomerId(toUUID(customerId)) : null); + entityView.setName(name); + try { + entityView.setKeys(new ObjectMapper().readValue(keys.toString(), new TypeReference>(){})); + } catch (IOException e) { + e.printStackTrace(); + } + entityView.setAdditionalInfo(additionalInfo); + return entityView; + } +} From 14fa80a26846de3e68c180c08400eb1cd01a35a1 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Fri, 31 Aug 2018 12:37:22 +0300 Subject: [PATCH 029/118] Was refactored --- .../org/thingsboard/server/common/data/EntityView.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) 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 b12e38e6b8..102f6eebec 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 @@ -15,9 +15,7 @@ */ package org.thingsboard.server.common.data; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; +import lombok.*; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityViewId; @@ -29,6 +27,7 @@ import java.util.List; /** * Created by Victor Basanets on 8/27/2017. */ + @Data @AllArgsConstructor @EqualsAndHashCode(callSuper = true) @@ -42,7 +41,7 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo private CustomerId customerId; private String name; private List keys; - private Long tsStart; + private Long tsBegin; private Long tsEnd; public EntityView() { From 76efea555c2a558a588bb818a26663abd978a7c7 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Fri, 31 Aug 2018 12:39:13 +0300 Subject: [PATCH 030/118] Was created sql & nosql entities --- .../dao/model/nosql/EntityViewEntity.java | 151 ++++++++++++++++++ .../dao/model/sql/EntityViewEntity.java | 20 ++- 2 files changed, 168 insertions(+), 3 deletions(-) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/model/nosql/EntityViewEntity.java 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 new file mode 100644 index 0000000000..c3227e9605 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EntityViewEntity.java @@ -0,0 +1,151 @@ +/** + * 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.model.nosql; + +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.core.type.TypeReference; +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.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.dao.model.ModelConstants; +import org.thingsboard.server.dao.model.SearchTextEntity; + +import javax.persistence.Column; + +import java.io.IOException; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_TABLE_FAMILY_NAME; +import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY; + +/** + * Created by Victor Basanets on 8/31/2017. + */ +@Data +@Table(name = ENTITY_VIEW_TABLE_FAMILY_NAME) +@EqualsAndHashCode +@ToString +public class EntityViewEntity implements SearchTextEntity { + + @PartitionKey(value = 0) + @Column(name = ID_PROPERTY) + private UUID id; + + @PartitionKey(value = 1) + @Column(name = ModelConstants.ENTITY_VIEW_ENTITY_ID_PROPERTY) + private UUID entityId; + + @PartitionKey(value = 2) + @Column(name = ModelConstants.ENTITY_VIEW_TENANT_ID_PROPERTY) + private UUID tenantId; + + @PartitionKey(value = 3) + @Column(name = ModelConstants.ENTITY_VIEW_CUSTOMER_ID_PROPERTY) + private UUID customerId; + + @Column(name = ModelConstants.ENTITY_VIEW_NAME_PROPERTY) + private String name; + + @Type(type = "json") + @Column(name = ModelConstants.ENTITY_VIEW_KEYS_PROPERTY) + private JsonNode keys; + + @Column(name = ModelConstants.ENTITY_VIEW_TS_BEGIN_PROPERTY) + private String tsBegin; + + @Column(name = ModelConstants.ENTITY_VIEW_TS_END_PROPERTY) + private String tsEnd; + + @Column(name = ModelConstants.SEARCH_TEXT_PROPERTY) + private String searchText; + + @Type(type = "json") + @Column(name = ModelConstants.ENTITY_VIEW_ADDITIONAL_INFO_PROPERTY) + private JsonNode additionalInfo; + + public EntityViewEntity() { + super(); + } + + public EntityViewEntity(EntityView entityView) { + if (entityView.getId() != null) { + this.id = entityView.getId().getId(); + } + if (entityView.getEntityId() != null) { + this.entityId = entityView.getEntityId().getId(); + } + if (entityView.getTenantId() != null) { + this.tenantId = entityView.getTenantId().getId(); + } + if (entityView.getCustomerId() != null) { + this.customerId = entityView.getCustomerId().getId(); + } + this.name = entityView.getName(); + try { + this.keys = new ObjectMapper().readTree("{\"" + entityView.getName() + "\" : [" + + entityView.getKeys().stream() + .map(k -> "\"" + k + "\"") + .collect(Collectors.joining(", ")) + "]}"); + } catch (IOException e) { + e.printStackTrace(); + } + this.tsBegin = String.valueOf(entityView.getTsBegin()); + this.tsEnd = String.valueOf(entityView.getTsEnd()); + this.additionalInfo = entityView.getAdditionalInfo(); + } + + @Override + public String getSearchTextSource() { + return name; + } + + @Override + public EntityView toData() { + EntityView entityView = new EntityView(new EntityViewId(id)); + entityView.setCreatedTime(UUIDs.unixTimestamp(id)); + if (entityId != null) { + entityView.setEntityId(new DeviceId(entityId)); + } + if (tenantId != null) { + entityView.setTenantId(new TenantId(tenantId)); + } + if (customerId != null) { + entityView.setCustomerId(new CustomerId(customerId)); + } + entityView.setName(name); + try { + entityView.setKeys(new ObjectMapper().readValue(keys.toString(), new TypeReference>(){})); + } catch (IOException e) { + e.printStackTrace(); + } + entityView.setTsBegin(Long.parseLong(tsBegin)); + entityView.setTsEnd(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 1444e9745e..dba075ce01 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 @@ -23,6 +23,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import org.hibernate.annotations.Type; 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.DeviceId; @@ -38,8 +39,13 @@ import javax.persistence.Entity; import javax.persistence.Table; import java.io.IOException; import java.util.List; +import java.util.UUID; import java.util.stream.Collectors; +/** + * Created by Victor Basanets on 8/30/2017. + */ + @Data @EqualsAndHashCode(callSuper = true) @Entity @@ -123,15 +129,23 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc entityView.setCreatedTime(UUIDs.unixTimestamp(getId())); /*Ned to refactor and replace DeviceId to Class<> instance*/ - entityView.setEntityId(entityId != null ? new DeviceId(toUUID(entityId)) : null); - entityView.setTenantId(tenantId != null ? new TenantId(toUUID(tenantId)) : null); - entityView.setCustomerId(customerId != null ? new CustomerId(toUUID(customerId)) : null); + if (entityId != null) { + entityView.setEntityId(new DeviceId(toUUID(entityId))); + } + if (tenantId != null) { + entityView.setTenantId(new TenantId(toUUID(tenantId))); + } + if (customerId != null) { + entityView.setCustomerId(new CustomerId(toUUID(customerId))); + } entityView.setName(name); try { entityView.setKeys(new ObjectMapper().readValue(keys.toString(), new TypeReference>(){})); } catch (IOException e) { e.printStackTrace(); } + entityView.setTsBegin(Long.parseLong(tsBegin)); + entityView.setTsEnd(Long.parseLong(tsEnd)); entityView.setAdditionalInfo(additionalInfo); return entityView; } From bc1e228dc117477c5840773858728c2fe3045131 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Fri, 31 Aug 2018 14:20:50 +0300 Subject: [PATCH 031/118] Was modified, method find(.*)Type renamed to find(.*)EntityId --- .../server/dao/entityview/EntityViewDao.java | 23 ++++++++----- .../dao/entityview/EntityViewService.java | 11 +++++-- .../dao/entityview/EntityViewServiceImpl.java | 33 ++++++++++--------- 3 files changed, 41 insertions(+), 26 deletions(-) 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 fbd1957db8..781cb3a68d 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 @@ -16,6 +16,7 @@ package org.thingsboard.server.dao.entityview; import org.thingsboard.server.common.data.EntityView; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.dao.Dao; @@ -47,14 +48,16 @@ public interface EntityViewDao extends Dao { Optional findEntityViewByTenantIdAndName(UUID tenantId, String name); /** - * Find entity views by tenantId, type and page link. + * Find entity views by tenantId, entityId and page link. * * @param tenantId the tenantId - * @param type the type + * @param entityId the entityId * @param pageLink the page link * @return the list of entity view objects */ - List findEntityViewByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink); + List findEntityViewByTenantIdAndEntityId(UUID tenantId, + EntityId entityId, + TextPageLink pageLink); /** * Find entity views by tenantId, customerId and page link. @@ -64,18 +67,22 @@ public interface EntityViewDao extends Dao { * @param pageLink the page link * @return the list of entity view objects */ - List findEntityViewsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink); + List findEntityViewsByTenantIdAndCustomerId(UUID tenantId, + UUID customerId, + TextPageLink pageLink); /** - * Find entity views by tenantId, customerId, type and page link. + * Find entity views by tenantId, customerId, entityId and page link. * * @param tenantId the tenantId * @param customerId the customerId - * @param type the type + * @param entityId the entityId * @param pageLink the page link * @return the list of entity view objects */ - List findEntityViewsByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, - TextPageLink pageLink); + List findEntityViewsByTenantIdAndCustomerIdAndEntityId(UUID tenantId, + UUID customerId, + EntityId entityId, + TextPageLink pageLink); } 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 8fcaf30dff..943d35e9b4 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,8 +15,10 @@ */ package org.thingsboard.server.dao.entityview; +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.page.TextPageData; @@ -41,15 +43,18 @@ public interface EntityViewService { TextPageData findEntityViewByTenantId(TenantId tenantId, TextPageLink pageLink); - TextPageData findEntityViewByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink); + TextPageData findEntityViewByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, + TextPageLink pageLink); void deleteEntityViewByTenantId(TenantId tenantId); TextPageData findEntityViewsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink); - TextPageData findEntityViewsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, - String type, TextPageLink pageLink); + TextPageData findEntityViewsByTenantIdAndCustomerIdAndEntityId(TenantId tenantId, + CustomerId customerId, + EntityId entityId, + TextPageLink pageLink); void unassignCustomerEntityViews(TenantId tenantId, CustomerId customerId); } 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 d7e9e9a192..e44cea552f 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 @@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.Tenant; 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.page.TextPageData; @@ -124,17 +125,17 @@ public class EntityViewServiceImpl extends AbstractEntityService } @Override - public TextPageData findEntityViewByTenantIdAndType(TenantId tenantId, String type, + public TextPageData findEntityViewByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, TextPageLink pageLink) { - log.trace("Executing findEntityViewByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", - tenantId, type, pageLink); + log.trace("Executing findEntityViewByTenantIdAndType, tenantId [{}], entityId [{}], pageLink [{}]", + tenantId, entityId, pageLink); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - validateString(type, "Incorrect type " + type); + validateString(entityId.toString(), "Incorrect entityId " + entityId.toString()); validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); - List entityViews = entityViewDao.findEntityViewByTenantIdAndType(tenantId.getId(), - type, pageLink); + List entityViews = entityViewDao.findEntityViewByTenantIdAndEntityId(tenantId.getId(), + entityId, pageLink); return new TextPageData<>(entityViews, pageLink); } @@ -150,8 +151,8 @@ public class EntityViewServiceImpl extends AbstractEntityService public TextPageData findEntityViewsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink) { - log.trace("Executing findEntityViewByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", - tenantId, customerId, pageLink); + log.trace("Executing findEntityViewByTenantIdAndCustomerId, tenantId [{}], customerId [{}]," + + " pageLink [{}]", tenantId, customerId, pageLink); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); @@ -163,18 +164,20 @@ public class EntityViewServiceImpl extends AbstractEntityService } @Override - public TextPageData findEntityViewsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, - String type, TextPageLink pageLink) { + public TextPageData findEntityViewsByTenantIdAndCustomerIdAndEntityId(TenantId tenantId, + CustomerId customerId, + EntityId entityId, + TextPageLink pageLink) { - log.trace("Executing findEntityViewsByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}], type [{}]," + - " pageLink [{}]", tenantId, customerId, type, pageLink); + log.trace("Executing findEntityViewsByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}]," + + " entityId [{}], pageLink [{}]", tenantId, customerId, entityId, pageLink); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); - validateString(type, "Incorrect type " + type); + validateString(entityId.toString(), "Incorrect entityId " + entityId.toString()); validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); - List entityViews = entityViewDao.findEntityViewsByTenantIdAndCustomerIdAndType(tenantId.getId(), - customerId.getId(), type, pageLink); + List entityViews = entityViewDao.findEntityViewsByTenantIdAndCustomerIdAndEntityId( + tenantId.getId(), customerId.getId(), entityId, pageLink); return new TextPageData<>(entityViews, pageLink); } From 7009cbd8acaba462105fb05f59881a0b4b5d55c9 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Fri, 31 Aug 2018 14:26:38 +0300 Subject: [PATCH 032/118] Was added asigning value to of 'searchText' field into constructors --- .../thingsboard/server/dao/model/nosql/EntityViewEntity.java | 1 + .../org/thingsboard/server/dao/model/sql/EntityViewEntity.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) 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 c3227e9605..a6d57829c7 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 @@ -116,6 +116,7 @@ public class EntityViewEntity implements SearchTextEntity { } this.tsBegin = String.valueOf(entityView.getTsBegin()); this.tsEnd = String.valueOf(entityView.getTsEnd()); + this.searchText = entityView.getSearchText(); this.additionalInfo = entityView.getAdditionalInfo(); } 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 dba075ce01..b12cf07976 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 @@ -39,7 +39,6 @@ import javax.persistence.Entity; import javax.persistence.Table; import java.io.IOException; import java.util.List; -import java.util.UUID; import java.util.stream.Collectors; /** @@ -110,6 +109,7 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc } this.tsBegin = String.valueOf(entityView.getTsBegin()); this.tsEnd = String.valueOf(entityView.getTsEnd()); + this.searchText = entityView.getSearchText(); this.additionalInfo = entityView.getAdditionalInfo(); } From de21d977a183bdadf8acfbb777b5ef5ac06c3157 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Fri, 31 Aug 2018 15:40:03 +0300 Subject: [PATCH 033/118] Was final changing --- .../org/thingsboard/server/dao/entityview/EntityViewDao.java | 4 ++-- .../server/dao/entityview/EntityViewServiceImpl.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) 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 781cb3a68d..25404db834 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 @@ -56,7 +56,7 @@ public interface EntityViewDao extends Dao { * @return the list of entity view objects */ List findEntityViewByTenantIdAndEntityId(UUID tenantId, - EntityId entityId, + UUID entityId, TextPageLink pageLink); /** @@ -82,7 +82,7 @@ public interface EntityViewDao extends Dao { */ List findEntityViewsByTenantIdAndCustomerIdAndEntityId(UUID tenantId, UUID customerId, - EntityId entityId, + UUID entityId, TextPageLink 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 e44cea552f..4a42577044 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 @@ -135,7 +135,7 @@ public class EntityViewServiceImpl extends AbstractEntityService validateString(entityId.toString(), "Incorrect entityId " + entityId.toString()); validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); List entityViews = entityViewDao.findEntityViewByTenantIdAndEntityId(tenantId.getId(), - entityId, pageLink); + entityId.getId(), pageLink); return new TextPageData<>(entityViews, pageLink); } @@ -177,7 +177,7 @@ public class EntityViewServiceImpl extends AbstractEntityService validateString(entityId.toString(), "Incorrect entityId " + entityId.toString()); validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); List entityViews = entityViewDao.findEntityViewsByTenantIdAndCustomerIdAndEntityId( - tenantId.getId(), customerId.getId(), entityId, pageLink); + tenantId.getId(), customerId.getId(), entityId.getId(), pageLink); return new TextPageData<>(entityViews, pageLink); } From 4fa083c7488ec14b3ee7b5c622a38e94e1b766ad Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Fri, 31 Aug 2018 16:01:10 +0300 Subject: [PATCH 034/118] Added dao impl --- .../sql/entityview/EntityViewRepository.java | 81 ++++++++++++++ .../dao/sql/entityview/JpaEntityViewDao.java | 100 ++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java 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 new file mode 100644 index 0000000000..27bd8395ac --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java @@ -0,0 +1,81 @@ +/** + * 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.sql.entityview; + +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.dao.model.sql.EntityViewEntity; +import org.thingsboard.server.dao.util.SqlDao; + +import java.util.List; + +/** + * Created by Victor Basanets on 8/31/2017. + */ +@SqlDao +public interface EntityViewRepository extends CrudRepository { + + @Query("SELECT e FROM EntityViewEntity e WHERE e.tenantId = :tenantId " + + "AND LOWER(e.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " + + "AND e.id > :idOffset ORDER BY e.id") + List findByTenantId(@Param("tenantId") String tenantId, + @Param("textSearch") String textSearch, + @Param("idOffset") String idOffset, + Pageable pageable); + + @Query("SELECT e FROM EntityViewEntity e WHERE e.tenantId = :tenantId " + + "AND e.entityId = :entityId " + + "AND LOWER(e.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " + + "AND e.id > :idOffset ORDER BY e.id") + List findByTenantIdAndEntityId(@Param("tenantId") String tenantId, + @Param("entityId") String entityId, + @Param("textSearch") String textSearch, + @Param("idOffset") String idOffset, + Pageable pageable); + + @Query("SELECT e FROM EntityViewEntity e WHERE e.tenantId = :tenantId " + + "AND e.customerId = :customerId " + + "AND LOWER(e.searchText) LIKE LOWER(CONCAT(:searchText, '%')) " + + "AND e.id > :idOffset ORDER BY e.id") + List findByTenantIdAndCustomerId(@Param("tenantId") String tenantId, + @Param("customerId") String customerId, + @Param("searchText") String searchText, + @Param("idOffset") String idOffset, + Pageable pageable); + + @Query("SELECT e FROM EntityViewEntity e WHERE e.tenantId = :tenantId " + + "AND e.customerId = :customerId " + + "AND e.entityId = :entityId " + + "AND LOWER(e.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " + + "AND e.id > :idOffset ORDER BY e.id") + List findByTenantIdAndCustomerIdAndEntityId(@Param("tenantId") String tenantId, + @Param("customerId") String customerId, + @Param("entityId") String entityId, + @Param("textSearch") String textSearch, + @Param("idOffset") String idOffset, + Pageable pageable); + + EntityViewEntity findByTenantIdAndName(String tenantId, String name); + + List findAllByTenantIdAndCustomerIdAndIdIn(String tenantId, + String customerId, + List entityViewsIds); + + List findAllByTenantIdAndIdIn(String tenantId, List entityViewsIds); +} 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 new file mode 100644 index 0000000000..82ac3e08c6 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java @@ -0,0 +1,100 @@ +package org.thingsboard.server.dao.sql.entityview; + +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.EntityView; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.page.TextPageLink; +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.sql.JpaAbstractSearchTextDao; +import org.thingsboard.server.dao.util.SqlDao; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + +import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUID; +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID_STR; + +@Component +@SqlDao +public class JpaEntityViewDao extends JpaAbstractSearchTextDao + implements EntityViewDao { + + @Autowired + EntityViewRepository entityViewRepository; + + @Override + protected Class getEntityClass() { + return EntityViewEntity.class; + } + + @Override + protected CrudRepository getCrudRepository() { + return entityViewRepository; + } + + @Override + public List findEntityViewByTenantId(UUID tenantId, TextPageLink pageLink) { + return DaoUtil.convertDataList( + entityViewRepository.findByTenantId( + fromTimeUUID(tenantId), + Objects.toString(pageLink.getTextSearch(), ""), + pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), + new PageRequest(0, pageLink.getLimit()))); + } + + @Override + public Optional findEntityViewByTenantIdAndName(UUID tenantId, String name) { + return Optional.ofNullable( + DaoUtil.getData(entityViewRepository.findByTenantIdAndName(fromTimeUUID(tenantId), name))); + } + + @Override + public List findEntityViewByTenantIdAndEntityId(UUID tenantId, + UUID entityId, + TextPageLink pageLink) { + return DaoUtil.convertDataList( + entityViewRepository.findByTenantIdAndEntityId( + fromTimeUUID(tenantId), + fromTimeUUID(entityId), + Objects.toString(pageLink.getTextSearch(), ""), + pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), + new PageRequest(0, pageLink.getLimit()))); + } + + @Override + public List findEntityViewsByTenantIdAndCustomerId(UUID tenantId, + UUID customerId, + TextPageLink pageLink) { + return DaoUtil.convertDataList( + entityViewRepository.findByTenantIdAndCustomerId( + fromTimeUUID(tenantId), + fromTimeUUID(customerId), + Objects.toString(pageLink, ""), + pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), + new PageRequest(0, pageLink.getLimit()) + )); + } + + @Override + public List findEntityViewsByTenantIdAndCustomerIdAndEntityId(UUID tenantId, + UUID customerId, + UUID entityId, + TextPageLink pageLink) { + return DaoUtil.convertDataList( + entityViewRepository.findByTenantIdAndCustomerIdAndEntityId( + fromTimeUUID(tenantId), + fromTimeUUID(customerId), + fromTimeUUID(entityId), + Objects.toString(pageLink, ""), + pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), + new PageRequest(0, pageLink.getLimit()) + )); + } +} From 65908b001c987df9f9bea616c49961806a98e21f Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 3 Sep 2018 19:23:38 +0300 Subject: [PATCH 035/118] Was modified an entity view constant --- .../java/org/thingsboard/server/dao/model/ModelConstants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 90ccb66ca0..e084593324 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 @@ -147,7 +147,7 @@ public class ModelConstants { /** * Cassandra entityView constants. */ - public static final String ENTITY_VIEW_TABLE_FAMILY_NAME = "entity_view"; + public static final String ENTITY_VIEW_TABLE_FAMILY_NAME = "entity_views"; public static final String ENTITY_VIEW_ENTITY_ID_PROPERTY = ENTITY_ID_COLUMN; public static final String ENTITY_VIEW_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; public static final String ENTITY_VIEW_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY; From 1f60a19dac20535a949a88aed6753a6d1e85232d Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 3 Sep 2018 19:26:42 +0300 Subject: [PATCH 036/118] Was added script to create new dbs for EntityView model --- dao/src/main/resources/cassandra/schema.cql | 42 +++++++++++++++++++++ dao/src/main/resources/sql/schema.sql | 13 +++++++ 2 files changed, 55 insertions(+) diff --git a/dao/src/main/resources/cassandra/schema.cql b/dao/src/main/resources/cassandra/schema.cql index f03122ab6b..bdd413d6ad 100644 --- a/dao/src/main/resources/cassandra/schema.cql +++ b/dao/src/main/resources/cassandra/schema.cql @@ -638,3 +638,45 @@ CREATE TABLE IF NOT EXISTS thingsboard.rule_node ( additional_info text, PRIMARY KEY (id) ); + +CREATE TABLE IF NOT EXISTS thingsboard.entity_views ( + id timeuuid, + entity_id timeuuid, + tenant_id timeuuid, + customer_id timeuuid, + name text, + keys text, + ts_begin bigint, + ts_end bigint, + 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 * + from thingsboard.entity_views + WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND ts_begin IS NOT NULL AND ts_end IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL + PRIMARY KEY (tenant_id, name, id, entity_id, customer_id) + WITH CLUSTERING ORDER BY (name ASC, id DESC, entity_id DESC, customer_id DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_entity AS + SELECT * + from thingsboard.entity_views + WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND ts_begin IS NOT NULL AND ts_end IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL + PRIMARY KEY (tenant_id, entity_id, id, customer_id, name) + WITH CLUSTERING ORDER BY (entity_id ASC, customer_id ASC, id DESC, name DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer AS + SELECT * + from thingsboard.entity_views + WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND ts_begin IS NOT NULL AND ts_end IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL + PRIMARY KEY (tenant_id, customer_id, id, entity_id, name) + WITH CLUSTERING ORDER BY (customer_id ASC, id DESC, entity_id DESC, name DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer_and_entity AS + SELECT * + from thingsboard.entity_views + WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND ts_begin IS NOT NULL AND ts_end IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL + PRIMARY KEY (tenant_id, customer_id, entity_id, id, name) + WITH CLUSTERING ORDER BY (customer_id ASC, entity_id DESC, id DESC, name DESC); diff --git a/dao/src/main/resources/sql/schema.sql b/dao/src/main/resources/sql/schema.sql index 91e77da503..8e21e72e9d 100644 --- a/dao/src/main/resources/sql/schema.sql +++ b/dao/src/main/resources/sql/schema.sql @@ -251,3 +251,16 @@ CREATE TABLE IF NOT EXISTS rule_node ( debug_mode boolean, search_text varchar(255) ); + +CREATE TABLE IF NOT EXISTS entity_views ( + id varchar(31) NOT NULL CONSTRAINT entity_view_pkey PRIMARY KEY, + additional_info varchar, + customer_id varchar(31), + keys varchar(255), + ts_begin varchar(255), + ts_end varchar(255), + name varchar(255), + search_text varchar(255), + entity_id varchar(31), + tenant_id varchar(31) +); From 8fdfa909dbc211ec5078e5bcdaa710ff37b92c7d Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 3 Sep 2018 19:30:48 +0300 Subject: [PATCH 037/118] Was modified classes to config and create DB for EntityView model --- .../server/install/ThingsboardInstallService.java | 7 +++++++ .../server/service/install/DefaultDataUpdateService.java | 4 ++++ .../service/install/SqlDatabaseUpgradeService.java | 9 +++++++++ 3 files changed, 20 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index f863d0bb2a..347b05409e 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -88,6 +88,13 @@ public class ThingsboardInstallService { dataUpdateService.updateData("1.4.0"); + case "2.0.0": + log.info("Upgrading ThingsBoard from version 2.0.0 to 2.1.1 ..."); + + databaseUpgradeService.upgradeDatabase("2.0.0"); + + dataUpdateService.updateData("2.0.0"); + log.info("Updating system data..."); systemDataLoaderService.deleteSystemWidgetBundle("charts"); diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultDataUpdateService.java index 5daebcc3c5..0194a5dfd7 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultDataUpdateService.java @@ -49,6 +49,10 @@ public class DefaultDataUpdateService implements DataUpdateService { log.info("Updating data from version 1.4.0 to 2.0.0 ..."); tenantsDefaultRuleChainUpdater.updateEntities(null); break; + case "2.0.0": + log.info("Updating data from version 2.0.0 to 2.1.1 ..."); + tenantsDefaultRuleChainUpdater.updateEntities(null); + break; default: throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion); } 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 3a4a837217..7d701b7a53 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 @@ -107,6 +107,15 @@ public class SqlDatabaseUpgradeService implements DatabaseUpgradeService { log.info("Schema updated."); } break; + case "2.0.0": + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { + log.info("Updating schema ..."); + schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.1.1", SCHEMA_UPDATE_SQL); + loadSql(schemaUpdateFile, conn); + log.info("Schema updated."); + } + break; + default: throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); } From 64620a89ceebe54731c9fb349098492dd51287cc Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 3 Sep 2018 19:32:29 +0300 Subject: [PATCH 038/118] Was add couple test methods --- .../sql/EntityViewControllerSqlTest.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/application/src/test/java/org/thingsboard/server/controller/sql/EntityViewControllerSqlTest.java b/application/src/test/java/org/thingsboard/server/controller/sql/EntityViewControllerSqlTest.java index 84e621fcf6..e10610ac6e 100644 --- a/application/src/test/java/org/thingsboard/server/controller/sql/EntityViewControllerSqlTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/sql/EntityViewControllerSqlTest.java @@ -15,13 +15,30 @@ */ package org.thingsboard.server.controller.sql; +import org.junit.Assert; +import org.junit.Test; +import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.controller.BaseEntityViewControllerTest; import org.thingsboard.server.dao.service.DaoSqlTest; +import java.util.Arrays; + /** * Created by Victor Basanets on 8/27/2017. */ @DaoSqlTest public class EntityViewControllerSqlTest extends BaseEntityViewControllerTest { + + @Test + public void testSaveEntityViewWithIdOfDevice() throws Exception { + super.testSaveEntityViewWithIdOfDevice(); + } + + @Test + public void testFindEntityViewById() throws Exception { + super.testFindEntityViewById(); + } + + } From 2cc562ed58cfc34675f5cced8fc853b90ef95b91 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 3 Sep 2018 19:48:01 +0300 Subject: [PATCH 039/118] Was added header --- .../dao/sql/entityview/JpaEntityViewDao.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) 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 82ac3e08c6..57b0afae8b 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 @@ -1,3 +1,18 @@ +/** + * 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.sql.entityview; import org.springframework.beans.factory.annotation.Autowired; @@ -21,6 +36,9 @@ import java.util.UUID; import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUID; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID_STR; +/** + * Created by Victor Basanets on 8/31/2017. + */ @Component @SqlDao public class JpaEntityViewDao extends JpaAbstractSearchTextDao From d24391a27632ed1fc638a93ffba55618a3400820 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Tue, 4 Sep 2018 10:45:39 +0300 Subject: [PATCH 040/118] Was added update for sql and cql --- .../main/data/upgrade/2.1.1/schema_update.cql | 91 +++++++++++++++++++ .../main/data/upgrade/2.1.1/schema_update.sql | 30 ++++++ 2 files changed, 121 insertions(+) create mode 100644 application/src/main/data/upgrade/2.1.1/schema_update.cql create mode 100644 application/src/main/data/upgrade/2.1.1/schema_update.sql 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 new file mode 100644 index 0000000000..c6fdf5a3b8 --- /dev/null +++ b/application/src/main/data/upgrade/2.1.1/schema_update.cql @@ -0,0 +1,91 @@ +/*-- +-- 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. +--*/ +DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_views_by_tenant_and_name; +DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_views_by_tenant_and_entity; +DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_views_by_tenant_and_customer; +DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_views_by_tenant_and_customer_and_entity; + +DROP TABLE IF EXISTS thingsboard.entity_views; + +CREATE TABLE IF NOT EXISTS thingsboard.entity_views ( + id timeuuid, + entity_id timeuuid, + tenant_id timeuuid, + customer_id timeuuid, + name text, + keys text, + ts_begin bigint, + ts_end bigint, + 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 * + from thingsboard.entity_views + WHERE entity_id IS NOT NULL + AND tenant_id IS NOT NULL + AND customer_id IS NOT NULL + AND keys IS NOT NULL + AND ts_begin IS NOT NULL + AND ts_end IS NOT NULL + AND name IS NOT NULL + AND id IS NOT NULL + PRIMARY KEY (tenant_id, name, id, entity_id, customer_id) + WITH CLUSTERING ORDER BY (name ASC, id DESC, entity_id DESC, customer_id DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_entity AS + SELECT * + from thingsboard.entity_views + WHERE entity_id IS NOT NULL + AND tenant_id IS NOT NULL + AND customer_id IS NOT NULL + AND keys IS NOT NULL + AND ts_begin IS NOT NULL + AND ts_end IS NOT NULL + AND name IS NOT NULL + AND id IS NOT NULL + PRIMARY KEY (tenant_id, entity_id, id, customer_id, name) + WITH CLUSTERING ORDER BY (entity_id ASC, customer_id ASC, id DESC, name DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer AS + SELECT * + from thingsboard.entity_views + WHERE entity_id IS NOT NULL + AND tenant_id IS NOT NULL + AND customer_id IS NOT NULL + AND keys IS NOT NULL + AND ts_begin IS NOT NULL + AND ts_end IS NOT NULL + AND name IS NOT NULL + AND id IS NOT NULL + PRIMARY KEY (tenant_id, customer_id, id, entity_id, name) + WITH CLUSTERING ORDER BY (customer_id ASC, id DESC, entity_id DESC, name DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer_and_entity AS + SELECT * + from thingsboard.entity_views + WHERE entity_id IS NOT NULL + AND tenant_id IS NOT NULL + AND customer_id IS NOT NULL + AND keys IS NOT NULL + AND ts_begin IS NOT NULL + AND ts_end IS NOT NULL + AND name IS NOT NULL + AND id IS NOT NULL + PRIMARY KEY (tenant_id, customer_id, entity_id, id, name) + WITH CLUSTERING ORDER BY (customer_id ASC, entity_id DESC, id DESC, name DESC); diff --git a/application/src/main/data/upgrade/2.1.1/schema_update.sql b/application/src/main/data/upgrade/2.1.1/schema_update.sql new file mode 100644 index 0000000000..f4754e99c9 --- /dev/null +++ b/application/src/main/data/upgrade/2.1.1/schema_update.sql @@ -0,0 +1,30 @@ +-- +-- 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. +-- + +DROP TABLE IF EXISTS entity_views; + +CREATE TABLE IF NOT EXISTS entity_views ( + id varchar(31) NOT NULL CONSTRAINT entity_views_pkey PRIMARY KEY, + additional_info varchar, + customer_id varchar(31), + keys varchar(255), + ts_begin varchar(255), + ts_end varchar(255), + name varchar(255), + search_text varchar(255), + entity_id varchar(31), + tenant_id varchar(31) +); From 0cb7f455f070902082e924a800b148f84c2b04d3 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Tue, 4 Sep 2018 11:05:52 +0300 Subject: [PATCH 041/118] Was modified header --- application/src/main/data/upgrade/2.1.1/schema_update.cql | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 c6fdf5a3b8..d9ba517df7 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 @@ -1,4 +1,4 @@ -/*-- +-- -- Copyright © 2016-2018 The Thingsboard Authors -- -- Licensed under the Apache License, Version 2.0 (the "License"); @@ -12,7 +12,8 @@ -- 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. ---*/ +-- + DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_views_by_tenant_and_name; DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_views_by_tenant_and_entity; DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_views_by_tenant_and_customer; From d28bd62b83da735a1a441eed5da5eb47c033fb89 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 5 Sep 2018 18:06:58 +0300 Subject: [PATCH 042/118] Was created classes for telemetry --- .../data/objects/AttributesEntityView.java | 47 +++++++++++++++++++ .../data/objects/TelemetryEntityView.java | 43 +++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/objects/AttributesEntityView.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/objects/TelemetryEntityView.java 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 new file mode 100644 index 0000000000..1c32579b72 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/objects/AttributesEntityView.java @@ -0,0 +1,47 @@ +/** + * 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.common.data.objects; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Victor Basanets on 9/05/2017. + */ +@Data +@NoArgsConstructor +public class AttributesEntityView { + + private List cs = new ArrayList<>(); + private List ss = new ArrayList<>(); + private List sh = new ArrayList<>(); + + public AttributesEntityView(List cs, + List ss, + List sh) { + + this.cs = new ArrayList<>(cs); + this.ss = new ArrayList<>(ss); + this.sh = new ArrayList<>(sh); + } + + public AttributesEntityView(AttributesEntityView obj) { + this(obj.getCs(), obj.getSs(), obj.getSh()); + } +} 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 new file mode 100644 index 0000000000..c899c65590 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/objects/TelemetryEntityView.java @@ -0,0 +1,43 @@ +/** + * 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.common.data.objects; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Victor Basanets on 9/05/2017. + */ +@Data +@NoArgsConstructor +public class TelemetryEntityView { + + private List timeseries; + private AttributesEntityView attributes; + + public TelemetryEntityView(List timeseries, AttributesEntityView attributes) { + + this.timeseries = new ArrayList<>(timeseries); + this.attributes = attributes; + } + + public TelemetryEntityView(TelemetryEntityView obj) { + this(obj.getTimeseries(), obj.getAttributes()); + } +} From 48ff2b2723bedffad829c9a9e756d05f62d9cf9b Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 5 Sep 2018 18:10:39 +0300 Subject: [PATCH 043/118] Was modified --- application/src/main/data/upgrade/2.1.1/schema_update.sql | 1 + .../java/org/thingsboard/server/common/data/EntityView.java | 6 ++---- .../thingsboard/server/common/data/id/EntityIdFactory.java | 2 ++ 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/application/src/main/data/upgrade/2.1.1/schema_update.sql b/application/src/main/data/upgrade/2.1.1/schema_update.sql index f4754e99c9..2fc953516f 100644 --- a/application/src/main/data/upgrade/2.1.1/schema_update.sql +++ b/application/src/main/data/upgrade/2.1.1/schema_update.sql @@ -26,5 +26,6 @@ CREATE TABLE IF NOT EXISTS entity_views ( name varchar(255), search_text varchar(255), entity_id varchar(31), + entity_type varchar(255), tenant_id varchar(31) ); 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 102f6eebec..03fce40cea 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 @@ -20,9 +20,7 @@ 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 java.beans.ConstructorProperties; -import java.util.List; +import org.thingsboard.server.common.data.objects.TelemetryEntityView; /** * Created by Victor Basanets on 8/27/2017. @@ -40,7 +38,7 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo private TenantId tenantId; private CustomerId customerId; private String name; - private List keys; + private TelemetryEntityView keys; //To Do: Changed from all code private Long tsBegin; private Long tsEnd; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java index ed4cf2f784..4e35c0b2df 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java @@ -57,6 +57,8 @@ public class EntityIdFactory { return new RuleChainId(uuid); case RULE_NODE: return new RuleNodeId(uuid); + case ENTITY_VIEW: + return new EntityViewId(uuid); } throw new IllegalArgumentException("EntityType " + type + " is not supported!"); } From 481d2f4770d376ae9363fe3c560d02e12549501a Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 5 Sep 2018 18:12:09 +0300 Subject: [PATCH 044/118] commit --- .../BaseEntityViewControllerTest.java | 26 +++++++++++++------ .../controller/ControllerSqlTestSuite.java | 2 +- .../nosql/EntityViewControllerNoSqlTest.java | 3 +-- .../sql/EntityViewControllerSqlTest.java | 15 +---------- 4 files changed, 21 insertions(+), 25 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index 7d9bae1901..c7ac98d413 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -23,6 +23,8 @@ 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.User; +import org.thingsboard.server.common.data.objects.AttributesEntityView; +import org.thingsboard.server.common.data.objects.TelemetryEntityView; import org.thingsboard.server.common.data.security.Authority; import java.util.Arrays; @@ -35,16 +37,12 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes private Tenant savedTenant; private User tenantAdmin; private Device testDevice; + private TelemetryEntityView obj; @Before public void beforeTest() throws Exception { loginSysAdmin(); - Device device = new Device(); - device.setName("Test device"); - device.setType("default"); - testDevice = doPost("/api/device", device, Device.class); - Tenant tenant = new Tenant(); tenant.setTitle("My tenant"); savedTenant = doPost("/api/tenant", tenant, Tenant.class); @@ -59,6 +57,18 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes tenantAdmin.setLastName("Downs"); tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); + + Device device = new Device(); + device.setName("Test device"); + device.setType("default"); + testDevice = doPost("/api/device", device, Device.class); + + obj = new TelemetryEntityView( + Arrays.asList("109L", "209L"), + new AttributesEntityView( + Arrays.asList("caKey1", "caKey2", "caKey3"), + Arrays.asList("saKey1", "saKey2", "saKey3", "saKey4"), + Arrays.asList("shKey1", "shKey2", "shKey3", "shKey4", "shKey5"))); } @After @@ -74,7 +84,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes EntityView view = new EntityView(); view.setName("Test entity view"); view.setEntityId(testDevice.getId()); - view.setKeys(Arrays.asList("key1", "key2", "key3")); + view.setKeys(new TelemetryEntityView(obj)); EntityView savedView = doPost("/api/entity-view", view, EntityView.class); EntityView foundView = doGet("/api/entity-view/" + savedView.getId().getId().toString(), EntityView.class); Assert.assertNotNull(foundView); @@ -87,7 +97,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes view.setEntityId(testDevice.getId()); view.setName("Test entity view"); view.setTenantId(savedTenant.getId()); - view.setKeys(Arrays.asList("key1", "key2", "key3")); + view.setKeys(new TelemetryEntityView(obj)); EntityView savedView = doPost("/api/entity-view", view, EntityView.class); Assert.assertNotNull(savedView); @@ -112,7 +122,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes EntityView view = new EntityView(); view.setName("Test entity view"); view.setEntityId(testDevice.getId()); - view.setKeys(Arrays.asList("key1", "key2", "key3")); + view.setKeys(new TelemetryEntityView((TelemetryEntityView) obj)); EntityView savedView = doPost("/api/entity-view", view, EntityView.class); doDelete("/api/entity-view/" + savedView.getId().getId().toString()) 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 f316051212..a9e94e9184 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.*SqlTest", + "org.thingsboard.server.controller.sql.EntityViewControllerSqlTest", }) 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 095edd19f8..ad066fc7ab 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 @@ -20,6 +20,5 @@ import org.thingsboard.server.controller.BaseEntityViewControllerTest; /** * Created by Victor Basanets on 8/27/2017. */ -public class EntityViewControllerNoSqlTest - extends BaseEntityViewControllerTest { +public class EntityViewControllerNoSqlTest extends BaseEntityViewControllerTest { } diff --git a/application/src/test/java/org/thingsboard/server/controller/sql/EntityViewControllerSqlTest.java b/application/src/test/java/org/thingsboard/server/controller/sql/EntityViewControllerSqlTest.java index e10610ac6e..76d99250c1 100644 --- a/application/src/test/java/org/thingsboard/server/controller/sql/EntityViewControllerSqlTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/sql/EntityViewControllerSqlTest.java @@ -27,18 +27,5 @@ import java.util.Arrays; * Created by Victor Basanets on 8/27/2017. */ @DaoSqlTest -public class EntityViewControllerSqlTest - extends BaseEntityViewControllerTest { - - @Test - public void testSaveEntityViewWithIdOfDevice() throws Exception { - super.testSaveEntityViewWithIdOfDevice(); - } - - @Test - public void testFindEntityViewById() throws Exception { - super.testFindEntityViewById(); - } - - +public class EntityViewControllerSqlTest extends BaseEntityViewControllerTest { } From 70ee36352816639472463caf089675411ba84005 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 5 Sep 2018 18:14:45 +0300 Subject: [PATCH 045/118] commit2 --- .../server/dao/model/ModelConstants.java | 1 + .../dao/model/nosql/EntityViewEntity.java | 32 ++++++--------- .../dao/model/sql/EntityViewEntity.java | 40 +++++++++---------- dao/src/main/resources/sql/schema.sql | 1 + 4 files changed, 34 insertions(+), 40 deletions(-) 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 e084593324..d06ddbd8e5 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 @@ -152,6 +152,7 @@ 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_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"; 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 a6d57829c7..65914dd566 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 @@ -18,9 +18,7 @@ package org.thingsboard.server.dao.model.nosql; 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.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -30,15 +28,14 @@ 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.objects.TelemetryEntityView; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.SearchTextEntity; import javax.persistence.Column; import java.io.IOException; -import java.util.List; import java.util.UUID; -import java.util.stream.Collectors; import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_TABLE_FAMILY_NAME; import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY; @@ -106,16 +103,13 @@ public class EntityViewEntity implements SearchTextEntity { this.customerId = entityView.getCustomerId().getId(); } this.name = entityView.getName(); - try { - this.keys = new ObjectMapper().readTree("{\"" + entityView.getName() + "\" : [" + - entityView.getKeys().stream() - .map(k -> "\"" + k + "\"") - .collect(Collectors.joining(", ")) + "]}"); - } catch (IOException e) { - e.printStackTrace(); - } - this.tsBegin = String.valueOf(entityView.getTsBegin()); - this.tsEnd = String.valueOf(entityView.getTsEnd()); +// 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"; this.searchText = entityView.getSearchText(); this.additionalInfo = entityView.getAdditionalInfo(); } @@ -139,11 +133,11 @@ public class EntityViewEntity implements SearchTextEntity { entityView.setCustomerId(new CustomerId(customerId)); } entityView.setName(name); - try { - entityView.setKeys(new ObjectMapper().readValue(keys.toString(), new TypeReference>(){})); - } catch (IOException e) { - e.printStackTrace(); - } +// try { +// entityView.setKeys((TelemetryEntityView) entityView.getKeys().toObject(keys)); +// } catch (IOException e) { +// e.printStackTrace(); +// } entityView.setTsBegin(Long.parseLong(tsBegin)); entityView.setTsEnd(Long.parseLong(tsEnd)); entityView.setAdditionalInfo(additionalInfo); 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 b12cf07976..62e9eb3e78 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 @@ -16,7 +16,6 @@ package org.thingsboard.server.dao.model.sql; import com.datastax.driver.core.utils.UUIDs; -import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.Data; @@ -25,21 +24,18 @@ import org.hibernate.annotations.Type; 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.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.BaseSqlEntity; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.SearchTextEntity; import org.thingsboard.server.dao.util.mapping.JsonStringType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Table; +import javax.persistence.*; import java.io.IOException; -import java.util.List; -import java.util.stream.Collectors; + +import static org.thingsboard.server.dao.model.ModelConstants.AUDIT_LOG_ENTITY_TYPE_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_TYPE_PROPERTY; /** * Created by Victor Basanets on 8/30/2017. @@ -64,9 +60,12 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc @Column(name = ModelConstants.ENTITY_VIEW_NAME_PROPERTY) private String name; - @Type(type = "json") + @Enumerated(EnumType.STRING) + @Column(name = ENTITY_TYPE_PROPERTY) + private EntityType entityType; + @Column(name = ModelConstants.ENTITY_VIEW_KEYS_PROPERTY) - private JsonNode keys; + private String keys; @Column(name = ModelConstants.ENTITY_VIEW_TS_BEGIN_PROPERTY) private String tsBegin; @@ -81,6 +80,8 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc @Column(name = ModelConstants.ENTITY_VIEW_ADDITIONAL_INFO_PROPERTY) private JsonNode additionalInfo; + private static final ObjectMapper mapper = new ObjectMapper(); + public EntityViewEntity() { super(); } @@ -91,6 +92,7 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc } if (entityView.getEntityId() != null) { this.entityId = toString(entityView.getEntityId().getId()); + this.entityType = entityView.getEntityId().getEntityType(); } if (entityView.getTenantId() != null) { this.tenantId = toString(entityView.getTenantId().getId()); @@ -100,15 +102,12 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc } this.name = entityView.getName(); try { - this.keys = new ObjectMapper().readTree("{\"" + entityView.getName() + "\" : [" + - entityView.getKeys().stream() - .map(k -> "\"" + k + "\"") - .collect(Collectors.joining(", ")) + "]}"); + this.keys = mapper.writeValueAsString(entityView.getKeys()); } catch (IOException e) { e.printStackTrace(); } - this.tsBegin = String.valueOf(entityView.getTsBegin()); - this.tsEnd = String.valueOf(entityView.getTsEnd()); + this.tsBegin = entityView.getTsBegin() != null ? String.valueOf(entityView.getTsBegin()) : ""; + this.tsEnd = entityView.getTsEnd() != null ? String.valueOf(entityView.getTsEnd()) : ""; this.searchText = entityView.getSearchText(); this.additionalInfo = entityView.getAdditionalInfo(); } @@ -128,9 +127,8 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc EntityView entityView = new EntityView(new EntityViewId(getId())); entityView.setCreatedTime(UUIDs.unixTimestamp(getId())); - /*Ned to refactor and replace DeviceId to Class<> instance*/ if (entityId != null) { - entityView.setEntityId(new DeviceId(toUUID(entityId))); + entityView.setEntityId(EntityIdFactory.getByTypeAndId(entityType.name(), toUUID(entityId).toString())); } if (tenantId != null) { entityView.setTenantId(new TenantId(toUUID(tenantId))); @@ -140,7 +138,7 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc } entityView.setName(name); try { - entityView.setKeys(new ObjectMapper().readValue(keys.toString(), new TypeReference>(){})); + entityView.setKeys(mapper.readValue(keys, TelemetryEntityView.class)); } catch (IOException e) { e.printStackTrace(); } diff --git a/dao/src/main/resources/sql/schema.sql b/dao/src/main/resources/sql/schema.sql index 8e21e72e9d..b79b61f3af 100644 --- a/dao/src/main/resources/sql/schema.sql +++ b/dao/src/main/resources/sql/schema.sql @@ -260,6 +260,7 @@ CREATE TABLE IF NOT EXISTS entity_views ( ts_begin varchar(255), ts_end varchar(255), name varchar(255), + entity_type varchar(255), search_text varchar(255), entity_id varchar(31), tenant_id varchar(31) From d731bf614e93c5e87b092bfb2f3bba2456ec8409 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 5 Sep 2018 19:29:42 +0300 Subject: [PATCH 046/118] commit3 --- .../src/main/data/upgrade/2.1.1/schema_update.sql | 12 ++++++------ .../thingsboard/server/common/data/EntityView.java | 2 +- .../common/data/objects/AttributesEntityView.java | 5 +++++ .../common/data/objects/TelemetryEntityView.java | 5 +++++ .../server/dao/entityview/EntityViewServiceImpl.java | 3 +-- .../server/dao/model/sql/EntityViewEntity.java | 8 ++++---- dao/src/main/resources/sql/schema.sql | 10 +++++----- 7 files changed, 27 insertions(+), 18 deletions(-) diff --git a/application/src/main/data/upgrade/2.1.1/schema_update.sql b/application/src/main/data/upgrade/2.1.1/schema_update.sql index 2fc953516f..3670aad035 100644 --- a/application/src/main/data/upgrade/2.1.1/schema_update.sql +++ b/application/src/main/data/upgrade/2.1.1/schema_update.sql @@ -17,15 +17,15 @@ DROP TABLE IF EXISTS entity_views; CREATE TABLE IF NOT EXISTS entity_views ( - id varchar(31) NOT NULL CONSTRAINT entity_views_pkey PRIMARY KEY, - additional_info varchar, + id varchar(31) NOT NULL CONSTRAINT entity_view_pkey PRIMARY KEY, + entity_id varchar(31), + entity_type varchar(255), + tenant_id varchar(31), customer_id varchar(31), + name varchar(255), keys varchar(255), ts_begin varchar(255), ts_end varchar(255), - name varchar(255), search_text varchar(255), - entity_id varchar(31), - entity_type varchar(255), - tenant_id varchar(31) + additional_info varchar ); 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 03fce40cea..813a9acd08 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 @@ -38,7 +38,7 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo private TenantId tenantId; private CustomerId customerId; private String name; - private TelemetryEntityView keys; //To Do: Changed from all code + private TelemetryEntityView keys; private Long tsBegin; private Long tsEnd; 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 1c32579b72..b1d270c934 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,4 +44,9 @@ 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 c899c65590..e7398e6500 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,4 +40,9 @@ 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/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index 4a42577044..6554083fe4 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 @@ -213,7 +213,7 @@ public class EntityViewServiceImpl extends AbstractEntityService @Override protected void validateDataImpl(EntityView entityView) { - if (StringUtils.isEmpty(String.join("", entityView.getKeys()))) { + if (StringUtils.isEmpty(entityView.getKeys().toString())) { throw new DataValidationException("Entity view type should be specified!"); } if (StringUtils.isEmpty(entityView.getName())) { @@ -272,6 +272,5 @@ public class EntityViewServiceImpl extends AbstractEntityService protected void removeEntity(EntityView entity) { unassignEntityViewFromCustomer(new EntityViewId(entity.getUuidId())); } - } } 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 62e9eb3e78..1175fac864 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 @@ -51,6 +51,10 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc @Column(name = ModelConstants.ENTITY_VIEW_ENTITY_ID_PROPERTY) private String entityId; + @Enumerated(EnumType.STRING) + @Column(name = ENTITY_TYPE_PROPERTY) + private EntityType entityType; + @Column(name = ModelConstants.ENTITY_VIEW_TENANT_ID_PROPERTY) private String tenantId; @@ -60,10 +64,6 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc @Column(name = ModelConstants.ENTITY_VIEW_NAME_PROPERTY) private String name; - @Enumerated(EnumType.STRING) - @Column(name = ENTITY_TYPE_PROPERTY) - private EntityType entityType; - @Column(name = ModelConstants.ENTITY_VIEW_KEYS_PROPERTY) private String keys; diff --git a/dao/src/main/resources/sql/schema.sql b/dao/src/main/resources/sql/schema.sql index b79b61f3af..ed3583cef3 100644 --- a/dao/src/main/resources/sql/schema.sql +++ b/dao/src/main/resources/sql/schema.sql @@ -254,14 +254,14 @@ CREATE TABLE IF NOT EXISTS rule_node ( CREATE TABLE IF NOT EXISTS entity_views ( id varchar(31) NOT NULL CONSTRAINT entity_view_pkey PRIMARY KEY, - additional_info varchar, + entity_id varchar(31), + entity_type varchar(255), + tenant_id varchar(31), customer_id varchar(31), + name varchar(255), keys varchar(255), ts_begin varchar(255), ts_end varchar(255), - name varchar(255), - entity_type varchar(255), search_text varchar(255), - entity_id varchar(31), - tenant_id varchar(31) + additional_info varchar ); From 8ecd9628ca0d983df07b18882e19c12a03f1130a Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Thu, 6 Sep 2018 10:08:39 +0300 Subject: [PATCH 047/118] The final modifications for passing preliminary tests --- .../thingsboard/server/dao/model/sql/EntityViewEntity.java | 4 ++-- dao/src/test/resources/sql/drop-all-tables.sql | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) 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 1175fac864..9136717fe3 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 @@ -106,8 +106,8 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc } catch (IOException e) { e.printStackTrace(); } - this.tsBegin = entityView.getTsBegin() != null ? String.valueOf(entityView.getTsBegin()) : ""; - this.tsEnd = entityView.getTsEnd() != null ? String.valueOf(entityView.getTsEnd()) : ""; + this.tsBegin = entityView.getTsBegin() != null ? String.valueOf(entityView.getTsBegin()) : "0"; + this.tsEnd = entityView.getTsEnd() != null ? String.valueOf(entityView.getTsEnd()) : "0"; this.searchText = entityView.getSearchText(); this.additionalInfo = entityView.getAdditionalInfo(); } diff --git a/dao/src/test/resources/sql/drop-all-tables.sql b/dao/src/test/resources/sql/drop-all-tables.sql index 23b6a56a47..ebc04b3938 100644 --- a/dao/src/test/resources/sql/drop-all-tables.sql +++ b/dao/src/test/resources/sql/drop-all-tables.sql @@ -18,4 +18,5 @@ DROP TABLE IF EXISTS user_credentials; DROP TABLE IF EXISTS widget_type; DROP TABLE IF EXISTS widgets_bundle; DROP TABLE IF EXISTS rule_node; -DROP TABLE IF EXISTS rule_chain; \ No newline at end of file +DROP TABLE IF EXISTS rule_chain; +DROP TABLE IF EXISTS entity_views; \ No newline at end of file From 40017c46dfc8ec59e093cc91bc83f0eed6a914c8 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Thu, 6 Sep 2018 10:23:58 +0300 Subject: [PATCH 048/118] Entity View feature - UI --- ui/src/app/api/entity-view.service.js | 237 +++++++++ ui/src/app/app.js | 2 + ui/src/app/common/types.constant.js | 3 +- .../app/entity-view/add-entity-view.tpl.html | 45 ++ ...add-entity-views-to-customer.controller.js | 123 +++++ .../add-entity-views-to-customer.tpl.html | 77 +++ .../assign-to-customer.controller.js | 123 +++++ .../entity-view/assign-to-customer.tpl.html | 76 +++ .../app/entity-view/entity-view-card.tpl.html | 22 + .../entity-view/entity-view-fieldset.tpl.html | 64 +++ .../app/entity-view/entity-view.controller.js | 483 ++++++++++++++++++ .../app/entity-view/entity-view.directive.js | 67 +++ ui/src/app/entity-view/entity-view.routes.js | 72 +++ ui/src/app/entity-view/entity-views.tpl.html | 83 +++ ui/src/app/entity-view/index.js | 41 ++ ui/src/app/locale/locale.constant-en_US.json | 73 +++ 16 files changed, 1590 insertions(+), 1 deletion(-) create mode 100644 ui/src/app/api/entity-view.service.js create mode 100644 ui/src/app/entity-view/add-entity-view.tpl.html create mode 100644 ui/src/app/entity-view/add-entity-views-to-customer.controller.js create mode 100644 ui/src/app/entity-view/add-entity-views-to-customer.tpl.html create mode 100644 ui/src/app/entity-view/assign-to-customer.controller.js create mode 100644 ui/src/app/entity-view/assign-to-customer.tpl.html create mode 100644 ui/src/app/entity-view/entity-view-card.tpl.html create mode 100644 ui/src/app/entity-view/entity-view-fieldset.tpl.html create mode 100644 ui/src/app/entity-view/entity-view.controller.js create mode 100644 ui/src/app/entity-view/entity-view.directive.js create mode 100644 ui/src/app/entity-view/entity-view.routes.js create mode 100644 ui/src/app/entity-view/entity-views.tpl.html create mode 100644 ui/src/app/entity-view/index.js diff --git a/ui/src/app/api/entity-view.service.js b/ui/src/app/api/entity-view.service.js new file mode 100644 index 0000000000..9bd8f8db08 --- /dev/null +++ b/ui/src/app/api/entity-view.service.js @@ -0,0 +1,237 @@ +/* + * 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. + */ +import thingsboardTypes from '../common/types.constant'; + +export default angular.module('thingsboard.api.entityView', [thingsboardTypes]) + .factory('entityViewService', EntityViewService) + .name; + +/*@ngInject*/ +function EntityViewService($http, $q, $window, userService, attributeService, customerService, types) { + + var service = { + assignEntityViewToCustomer: assignEntityViewToCustomer, + deleteEntityView: deleteEntityView, + getCustomerEntityViews: getCustomerEntityViews, + getEntityView: getEntityView, + getEntityViews: getEntityViews, + getTenantEntityViews: getTenantEntityViews, + saveEntityView: saveEntityView, + unassignEntityViewFromCustomer: unassignEntityViewFromCustomer, + getEntityViewAttributes: getEntityViewAttributes, + subscribeForEntityViewAttributes: subscribeForEntityViewAttributes, + unsubscribeForEntityViewAttributes: unsubscribeForEntityViewAttributes, + findByQuery: findByQuery, + getEntityViewTypes: getEntityViewTypes + } + + return service; + + function getTenantEntityViews(pageLink, applyCustomersInfo, config, type) { + var deferred = $q.defer(); + var url = '/api/tenant/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; + } + $http.get(url, config).then(function success(response) { + if (applyCustomersInfo) { + customerService.applyAssignedCustomersInfo(response.data.data).then( + function success(data) { + response.data.data = data; + deferred.resolve(response.data); + }, + function fail() { + deferred.reject(); + } + ); + } else { + deferred.resolve(response.data); + } + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function getCustomerEntityViews(customerId, pageLink, applyCustomersInfo, config, type) { + var deferred = $q.defer(); + var url = '/api/customer/' + customerId + '/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; + } + $http.get(url, config).then(function success(response) { + if (applyCustomersInfo) { + customerService.applyAssignedCustomerInfo(response.data.data, customerId).then( + function success(data) { + response.data.data = data; + deferred.resolve(response.data); + }, + function fail() { + deferred.reject(); + } + ); + } else { + deferred.resolve(response.data); + } + }, function fail() { + deferred.reject(); + }); + + return deferred.promise; + } + + function getEntityView(entityViewId, ignoreErrors, config) { + var deferred = $q.defer(); + var url = '/api/entityView/' + entityViewId; + if (!config) { + config = {}; + } + config = Object.assign(config, { ignoreErrors: ignoreErrors }); + $http.get(url, config).then(function success(response) { + deferred.resolve(response.data); + }, function fail(response) { + deferred.reject(response.data); + }); + return deferred.promise; + } + + function getEntityViews(entityViewIds, config) { + var deferred = $q.defer(); + var ids = ''; + for (var i=0;i0) { + ids += ','; + } + ids += entityViewIds[i]; + } + var url = '/api/entityViews?entityViewIds=' + ids; + $http.get(url, config).then(function success(response) { + var entityViews = response.data; + entityViews.sort(function (entityView1, entityView2) { + var id1 = entityView1.id.id; + var id2 = entityView2.id.id; + var index1 = entityViewIds.indexOf(id1); + var index2 = entityViewIds.indexOf(id2); + return index1 - index2; + }); + deferred.resolve(entityViews); + }, function fail(response) { + deferred.reject(response.data); + }); + return deferred.promise; + } + + function saveEntityView(entityView) { + var deferred = $q.defer(); + var url = '/api/entityView'; + $http.post(url, entityView).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function deleteEntityView(entityViewId) { + var deferred = $q.defer(); + var url = '/api/entityView/' + entityViewId; + $http.delete(url).then(function success() { + deferred.resolve(); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function assignEntityViewToCustomer(customerId, entityViewId) { + var deferred = $q.defer(); + var url = '/api/customer/' + customerId + '/entityView/' + entityViewId; + $http.post(url, null).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function unassignEntityViewFromCustomer(entityViewId) { + var deferred = $q.defer(); + var url = '/api/customer/entityView/' + entityViewId; + $http.delete(url).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function getEntityViewAttributes(entityViewId, attributeScope, query, successCallback, config) { + return attributeService.getEntityAttributes(types.entityType.entityView, entityViewId, attributeScope, query, successCallback, config); + } + + function subscribeForEntityViewAttributes(entityViewId, attributeScope) { + return attributeService.subscribeForEntityAttributes(types.entityType.entityView, entityViewId, attributeScope); + } + + function unsubscribeForEntityViewAttributes(subscriptionId) { + attributeService.unsubscribeForEntityAttributes(subscriptionId); + } + + function findByQuery(query, ignoreErrors, config) { + var deferred = $q.defer(); + var url = '/api/entityViews'; + if (!config) { + config = {}; + } + config = Object.assign(config, { ignoreErrors: ignoreErrors }); + $http.post(url, query, config).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function getEntityViewTypes(config) { + var deferred = $q.defer(); + var url = '/api/entityView/types'; + $http.get(url, config).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + +} diff --git a/ui/src/app/app.js b/ui/src/app/app.js index c8cdeb02b0..a3a179eb12 100644 --- a/ui/src/app/app.js +++ b/ui/src/app/app.js @@ -67,6 +67,7 @@ import thingsboardClipboard from './services/clipboard.service'; import thingsboardHome from './layout'; import thingsboardApiLogin from './api/login.service'; import thingsboardApiDevice from './api/device.service'; +import thingsboardApiEntityView from './api/entity-view.service'; import thingsboardApiUser from './api/user.service'; import thingsboardApiEntityRelation from './api/entity-relation.service'; import thingsboardApiAsset from './api/asset.service'; @@ -133,6 +134,7 @@ angular.module('thingsboard', [ thingsboardHome, thingsboardApiLogin, thingsboardApiDevice, + thingsboardApiEntityView, thingsboardApiUser, thingsboardApiEntityRelation, thingsboardApiAsset, diff --git a/ui/src/app/common/types.constant.js b/ui/src/app/common/types.constant.js index 1e34577119..1d1b7171c3 100644 --- a/ui/src/app/common/types.constant.js +++ b/ui/src/app/common/types.constant.js @@ -327,7 +327,8 @@ export default angular.module('thingsboard.types', []) dashboard: "DASHBOARD", alarm: "ALARM", rulechain: "RULE_CHAIN", - rulenode: "RULE_NODE" + rulenode: "RULE_NODE", + entityview: "ENTITY_VIEW" }, aliasEntityType: { current_customer: "CURRENT_CUSTOMER" diff --git a/ui/src/app/entity-view/add-entity-view.tpl.html b/ui/src/app/entity-view/add-entity-view.tpl.html new file mode 100644 index 0000000000..48a1788ed0 --- /dev/null +++ b/ui/src/app/entity-view/add-entity-view.tpl.html @@ -0,0 +1,45 @@ + + +
+ +
+

entity-view.add

+ +
+ + + +
+
+ + + +
+ +
+
+ + + + {{ 'action.add' | translate }} + + {{ 'action.cancel' | translate }} + +
+
\ No newline at end of file diff --git a/ui/src/app/entity-view/add-entity-views-to-customer.controller.js b/ui/src/app/entity-view/add-entity-views-to-customer.controller.js new file mode 100644 index 0000000000..8e39546ffd --- /dev/null +++ b/ui/src/app/entity-view/add-entity-views-to-customer.controller.js @@ -0,0 +1,123 @@ +/* + * 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. + */ +/*@ngInject*/ +export default function AddEntityViewsToCustomerController(entityViewService, $mdDialog, $q, customerId, entityViews) { + + var vm = this; + + vm.entityViews = entityViews; + vm.searchText = ''; + + vm.assign = assign; + vm.cancel = cancel; + vm.hasData = hasData; + vm.noData = noData; + vm.searchEntityViewTextUpdated = searchEntityViewTextUpdated; + vm.toggleEntityViewSelection = toggleEntityViewSelection; + + vm.theEntityViews = { + getItemAtIndex: function (index) { + if (index > vm.entityViews.data.length) { + vm.theEntityViews.fetchMoreItems_(index); + return null; + } + var item = vm.entityViews.data[index]; + if (item) { + item.indexNumber = index + 1; + } + return item; + }, + + getLength: function () { + if (vm.entityViews.hasNext) { + return vm.entityViews.data.length + vm.entityViews.nextPageLink.limit; + } else { + return vm.entityViews.data.length; + } + }, + + fetchMoreItems_: function () { + if (vm.entityViews.hasNext && !vm.entityViews.pending) { + vm.entityViews.pending = true; + entityViewService.getTenantEntityViews(vm.entityViews.nextPageLink, false).then( + function success(entityViews) { + vm.entityViews.data = vm.entityViews.data.concat(entityViews.data); + vm.entityViews.nextPageLink = entityViews.nextPageLink; + vm.entityViews.hasNext = entityViews.hasNext; + if (vm.entityViews.hasNext) { + vm.entityViews.nextPageLink.limit = vm.entityViews.pageSize; + } + vm.entityViews.pending = false; + }, + function fail() { + vm.entityViews.hasNext = false; + vm.entityViews.pending = false; + }); + } + } + }; + + function cancel () { + $mdDialog.cancel(); + } + + function assign() { + var tasks = []; + for (var entityViewId in vm.entityViews.selections) { + tasks.push(entityViewService.assignEntityViewToCustomer(customerId, entityViewId)); + } + $q.all(tasks).then(function () { + $mdDialog.hide(); + }); + } + + function noData() { + return vm.entityViews.data.length == 0 && !vm.entityViews.hasNext; + } + + function hasData() { + return vm.entityViews.data.length > 0; + } + + function toggleEntityViewSelection($event, entityView) { + $event.stopPropagation(); + var selected = angular.isDefined(entityView.selected) && entityView.selected; + entityView.selected = !selected; + if (entityView.selected) { + vm.entityViews.selections[entityView.id.id] = true; + vm.entityViews.selectedCount++; + } else { + delete vm.entityViews.selections[entityView.id.id]; + vm.entityViews.selectedCount--; + } + } + + function searchEntityViewTextUpdated() { + vm.entityViews = { + pageSize: vm.entityViews.pageSize, + data: [], + nextPageLink: { + limit: vm.entityViews.pageSize, + textSearch: vm.searchText + }, + selections: {}, + selectedCount: 0, + hasNext: true, + pending: false + }; + } + +} diff --git a/ui/src/app/entity-view/add-entity-views-to-customer.tpl.html b/ui/src/app/entity-view/add-entity-views-to-customer.tpl.html new file mode 100644 index 0000000000..1149a1d8be --- /dev/null +++ b/ui/src/app/entity-view/add-entity-views-to-customer.tpl.html @@ -0,0 +1,77 @@ + + +
+ +
+

entity-view.assign-entity-view-to-customer

+ + + + +
+
+ + + +
+
+ entity-view.assign-entity-view-to-customer-text + + + + search + + + +
+ entity-view.no-entity-views-text + + + + + {{ entityView.name }} + + + +
+
+
+
+ + + + {{ 'action.assign' | translate }} + + {{ 'action.cancel' | + translate }} + + +
+
\ No newline at end of file diff --git a/ui/src/app/entity-view/assign-to-customer.controller.js b/ui/src/app/entity-view/assign-to-customer.controller.js new file mode 100644 index 0000000000..3e09ae6e4f --- /dev/null +++ b/ui/src/app/entity-view/assign-to-customer.controller.js @@ -0,0 +1,123 @@ +/* + * 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. + */ +/*@ngInject*/ +export default function AssignEntityViewToCustomerController(customerService, entityViewService, $mdDialog, $q, entityViewIds, customers) { + + var vm = this; + + vm.customers = customers; + vm.searchText = ''; + + vm.assign = assign; + vm.cancel = cancel; + vm.isCustomerSelected = isCustomerSelected; + vm.hasData = hasData; + vm.noData = noData; + vm.searchCustomerTextUpdated = searchCustomerTextUpdated; + vm.toggleCustomerSelection = toggleCustomerSelection; + + vm.theCustomers = { + getItemAtIndex: function (index) { + if (index > vm.customers.data.length) { + vm.theCustomers.fetchMoreItems_(index); + return null; + } + var item = vm.customers.data[index]; + if (item) { + item.indexNumber = index + 1; + } + return item; + }, + + getLength: function () { + if (vm.customers.hasNext) { + return vm.customers.data.length + vm.customers.nextPageLink.limit; + } else { + return vm.customers.data.length; + } + }, + + fetchMoreItems_: function () { + if (vm.customers.hasNext && !vm.customers.pending) { + vm.customers.pending = true; + customerService.getCustomers(vm.customers.nextPageLink).then( + function success(customers) { + vm.customers.data = vm.customers.data.concat(customers.data); + vm.customers.nextPageLink = customers.nextPageLink; + vm.customers.hasNext = customers.hasNext; + if (vm.customers.hasNext) { + vm.customers.nextPageLink.limit = vm.customers.pageSize; + } + vm.customers.pending = false; + }, + function fail() { + vm.customers.hasNext = false; + vm.customers.pending = false; + }); + } + } + }; + + function cancel() { + $mdDialog.cancel(); + } + + function assign() { + var tasks = []; + for (var i=0; i < entityViewIds.length;i++) { + tasks.push(entityViewService.assignEntityViewToCustomer(vm.customers.selection.id.id, entityViewIds[i])); + } + $q.all(tasks).then(function () { + $mdDialog.hide(); + }); + } + + function noData() { + return vm.customers.data.length == 0 && !vm.customers.hasNext; + } + + function hasData() { + return vm.customers.data.length > 0; + } + + function toggleCustomerSelection($event, customer) { + $event.stopPropagation(); + if (vm.isCustomerSelected(customer)) { + vm.customers.selection = null; + } else { + vm.customers.selection = customer; + } + } + + function isCustomerSelected(customer) { + return vm.customers.selection != null && customer && + customer.id.id === vm.customers.selection.id.id; + } + + function searchCustomerTextUpdated() { + vm.customers = { + pageSize: vm.customers.pageSize, + data: [], + nextPageLink: { + limit: vm.customers.pageSize, + textSearch: vm.searchText + }, + selection: null, + hasNext: true, + pending: false + }; + } +} diff --git a/ui/src/app/entity-view/assign-to-customer.tpl.html b/ui/src/app/entity-view/assign-to-customer.tpl.html new file mode 100644 index 0000000000..7c1fa2540e --- /dev/null +++ b/ui/src/app/entity-view/assign-to-customer.tpl.html @@ -0,0 +1,76 @@ + + +
+ +
+

entity-view.assign-entity-view-to-customer

+ + + + +
+
+ + + +
+
+ entity-view.assign-to-customer-text + + + + search + + + +
+ customer.no-customers-text + + + + + {{ customer.title }} + + + +
+
+
+
+ + + + {{ 'action.assign' | translate }} + + {{ 'action.cancel' | + translate }} + + +
+
\ No newline at end of file diff --git a/ui/src/app/entity-view/entity-view-card.tpl.html b/ui/src/app/entity-view/entity-view-card.tpl.html new file mode 100644 index 0000000000..1e90928540 --- /dev/null +++ b/ui/src/app/entity-view/entity-view-card.tpl.html @@ -0,0 +1,22 @@ + +
+
{{vm.item.type}}
+
{{vm.item.additionalInfo.description}}
+
{{'entity-view.assignedToCustomer' | translate}} '{{vm.item.assignedCustomer.title}}'
+
diff --git a/ui/src/app/entity-view/entity-view-fieldset.tpl.html b/ui/src/app/entity-view/entity-view-fieldset.tpl.html new file mode 100644 index 0000000000..e0000c6d9d --- /dev/null +++ b/ui/src/app/entity-view/entity-view-fieldset.tpl.html @@ -0,0 +1,64 @@ + +{{ 'entity-view.assign-to-customer' | translate }} +{{'entity-view.unassign-from-customer' | translate }} +{{ 'entity-view.delete' | translate }} + +
+ + + entity-view.copyId + +
+ + + + + + +
+ + + +
+
entity-view.name-required
+
+
+ + + + + + +
+
diff --git a/ui/src/app/entity-view/entity-view.controller.js b/ui/src/app/entity-view/entity-view.controller.js new file mode 100644 index 0000000000..fd3b5a836a --- /dev/null +++ b/ui/src/app/entity-view/entity-view.controller.js @@ -0,0 +1,483 @@ +/* + * 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. + */ +/* eslint-disable import/no-unresolved, import/default */ + +import addEntityViewTemplate from './add-entity-view.tpl.html'; +import entityViewCard from './entity-view-card.tpl.html'; +import assignToCustomerTemplate from './assign-to-customer.tpl.html'; +import addEntityViewsToCustomerTemplate from './add-entity-views-to-customer.tpl.html'; + +/* eslint-enable import/no-unresolved, import/default */ + +/*@ngInject*/ +export function EntityViewCardController(types) { + + var vm = this; + + vm.types = types; + + vm.isAssignedToCustomer = function() { + if (vm.item && vm.item.customerId && vm.parentCtl.entityViewsScope === 'tenant' && + vm.item.customerId.id != vm.types.id.nullUid && !vm.item.assignedCustomer.isPublic) { + return true; + } + return false; + } + + vm.isPublic = function() { + if (vm.item && vm.item.assignedCustomer && vm.parentCtl.entityViewsScope === 'tenant' && vm.item.assignedCustomer.isPublic) { + return true; + } + return false; + } +} + + +/*@ngInject*/ +export function EntityViewController($rootScope, userService, entityViewService, customerService, $state, $stateParams, + $document, $mdDialog, $q, $translate, types) { + + var customerId = $stateParams.customerId; + + var entityViewActionsList = []; + + var entityViewGroupActionsList = []; + + var vm = this; + + vm.types = types; + + vm.entityViewGridConfig = { + deleteItemTitleFunc: deleteEntityViewTitle, + deleteItemContentFunc: deleteEntityViewText, + deleteItemsTitleFunc: deleteEntityViewsTitle, + deleteItemsActionTitleFunc: deleteEntityViewsActionTitle, + deleteItemsContentFunc: deleteEntityViewsText, + + saveItemFunc: saveEntityView, + + getItemTitleFunc: getEntityViewTitle, + + itemCardController: 'EntityViewCardController', + itemCardTemplateUrl: entityViewCard, + parentCtl: vm, + + actionsList: entityViewActionsList, + groupActionsList: entityViewGroupActionsList, + + onGridInited: gridInited, + + addItemTemplateUrl: addEntityViewTemplate, + + addItemText: function() { return $translate.instant('entity-view.add-entity-view-text') }, + noItemsText: function() { return $translate.instant('entity-view.no-entity-views-text') }, + itemDetailsText: function() { return $translate.instant('entity-view.entity-view-details') }, + isDetailsReadOnly: isCustomerUser, + isSelectionEnabled: function () { + return !isCustomerUser(); + } + }; + + if (angular.isDefined($stateParams.items) && $stateParams.items !== null) { + vm.entityViewGridConfig.items = $stateParams.items; + } + + if (angular.isDefined($stateParams.topIndex) && $stateParams.topIndex > 0) { + vm.entityViewGridConfig.topIndex = $stateParams.topIndex; + } + + vm.entityViewsScope = $state.$current.data.entityViewsType; + + vm.assignToCustomer = assignToCustomer; + vm.makePublic = makePublic; + vm.unassignFromCustomer = unassignFromCustomer; + + initController(); + + function initController() { + var fetchEntityViewsFunction = null; + var deleteEntityViewFunction = null; + var refreshEntityViewsParamsFunction = null; + + var user = userService.getCurrentUser(); + + if (user.authority === 'CUSTOMER_USER') { + vm.entityViewsScope = 'customer_user'; + customerId = user.customerId; + } + if (customerId) { + vm.customerEntityViewsTitle = $translate.instant('customer.entity-views'); + customerService.getShortCustomerInfo(customerId).then( + function success(info) { + if (info.isPublic) { + vm.customerEntityViewsTitle = $translate.instant('customer.public-entity-views'); + } + } + ); + } + + if (vm.entityViewsScope === 'tenant') { + fetchEntityViewsFunction = function (pageLink, entityViewType) { + return entityViewService.getTenantEntityViews(pageLink, true, null, entityViewType); + }; + deleteEntityViewFunction = function (entityViewId) { + return entityViewService.deleteEntityView(entityViewId); + }; + refreshEntityViewsParamsFunction = function() { + return {"topIndex": vm.topIndex}; + }; + + entityViewActionsList.push( + { + onAction: function ($event, item) { + assignToCustomer($event, [ item.id.id ]); + }, + name: function() { return $translate.instant('action.assign') }, + details: function() { return $translate.instant('entity-view.assign-to-customer') }, + icon: "assignment_ind", + isEnabled: function(entityView) { + return entityView && (!entityView.customerId || entityView.customerId.id === types.id.nullUid); + } + } + ); + + entityViewActionsList.push( + { + onAction: function ($event, item) { + unassignFromCustomer($event, item, false); + }, + name: function() { return $translate.instant('action.unassign') }, + details: function() { return $translate.instant('entity-view.unassign-from-customer') }, + icon: "assignment_return", + isEnabled: function(entityView) { + return entityView && entityView.customerId && entityView.customerId.id !== types.id.nullUid && !entityView.assignedCustomer.isPublic; + } + } + ); + + entityViewActionsList.push({ + onAction: function ($event, item) { + unassignFromCustomer($event, item, true); + }, + name: function() { return $translate.instant('action.make-private') }, + details: function() { return $translate.instant('entity-view.make-private') }, + icon: "reply", + isEnabled: function(entityView) { + return entityView && entityView.customerId && entityView.customerId.id !== types.id.nullUid && entityView.assignedCustomer.isPublic; + } + }); + + entityViewActionsList.push( + { + onAction: function ($event, item) { + vm.grid.deleteItem($event, item); + }, + name: function() { return $translate.instant('action.delete') }, + details: function() { return $translate.instant('entity-view.delete') }, + icon: "delete" + } + ); + + entityViewGroupActionsList.push( + { + onAction: function ($event, items) { + assignEntiyViewsToCustomer($event, items); + }, + name: function() { return $translate.instant('entity-view.assign-entity-views') }, + details: function(selectedCount) { + return $translate.instant('entity-view.assign-entity-views-text', {count: selectedCount}, "messageformat"); + }, + icon: "assignment_ind" + } + ); + + entityViewGroupActionsList.push( + { + onAction: function ($event) { + vm.grid.deleteItems($event); + }, + name: function() { return $translate.instant('entity-view.delete-entity-views') }, + details: deleteEntityViewsActionTitle, + icon: "delete" + } + ); + + + + } else if (vm.entityViewsScope === 'customer' || vm.entityViewsScope === 'customer_user') { + fetchEntityViewsFunction = function (pageLink, entityViewType) { + return entityViewService.getCustomerEntityViews(customerId, pageLink, true, null, entityViewType); + }; + deleteentityViewFunction = function (entityViewId) { + return entityViewService.unassignEntityViewFromCustomer(entityViewId); + }; + refreshentityViewsParamsFunction = function () { + return {"customerId": customerId, "topIndex": vm.topIndex}; + }; + + if (vm.entityViewsScope === 'customer') { + entityViewActionsList.push( + { + onAction: function ($event, item) { + unassignFromCustomer($event, item, false); + }, + name: function() { return $translate.instant('action.unassign') }, + details: function() { return $translate.instant('entity-view.unassign-from-customer') }, + icon: "assignment_return", + isEnabled: function(entityView) { + return entityView && !entityView.assignedCustomer.isPublic; + } + } + ); + + entityViewGroupActionsList.push( + { + onAction: function ($event, items) { + unassignEntityViewsFromCustomer($event, items); + }, + 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"); + }, + icon: "assignment_return" + } + ); + + vm.entityViewGridConfig.addItemAction = { + onAction: function ($event) { + addEntityViewsToCustomer($event); + }, + name: function() { return $translate.instant('entity-view.assign-entity-views') }, + details: function() { return $translate.instant('entity-view.assign-new-entity-view') }, + icon: "add" + }; + + + } else if (vm.entityViewsScope === 'customer_user') { + vm.entityViewGridConfig.addItemAction = {}; + } + } + + vm.entityViewGridConfig.refreshParamsFunc = refreshentityViewsParamsFunction; + vm.entityViewGridConfig.fetchItemsFunc = fetchentityViewsFunction; + vm.entityViewGridConfig.deleteItemFunc = deleteentityViewFunction; + + } + + function deleteEntityViewTitle(entityView) { + return $translate.instant('entity-view.delete-entity-view-title', {entityViewName: entityView.name}); + } + + function deleteEntityViewText() { + return $translate.instant('entity-view.delete-entity-view-text'); + } + + function deleteEntityViewsTitle(selectedCount) { + return $translate.instant('entity-view.delete-entity-views-title', {count: selectedCount}, 'messageformat'); + } + + function deleteEntityViewsActionTitle(selectedCount) { + return $translate.instant('entity-view.delete-entity-views-action-title', {count: selectedCount}, 'messageformat'); + } + + function deleteEntityViewsText () { + return $translate.instant('entity-view.delete-entity-views-text'); + } + + function gridInited(grid) { + vm.grid = grid; + } + + function getEntityViewTitle(entityView) { + return entityView ? entityView.name : ''; + } + + function saveEntityView(entityView) { + var deferred = $q.defer(); + entityViewService.saveEntityView(entityView).then( + function success(savedEntityView) { + $rootScope.$broadcast('entityViewSaved'); + var entityViews = [ savedEntityView ]; + customerService.applyAssignedCustomersInfo(entityViews).then( + function success(items) { + if (items && items.length == 1) { + deferred.resolve(items[0]); + } else { + deferred.reject(); + } + }, + function fail() { + deferred.reject(); + } + ); + }, + function fail() { + deferred.reject(); + } + ); + return deferred.promise; + } + + function isCustomerUser() { + return vm.entityViewsScope === 'customer_user'; + } + + function assignToCustomer($event, entityViewIds) { + if ($event) { + $event.stopPropagation(); + } + var pageSize = 10; + customerService.getCustomers({limit: pageSize, textSearch: ''}).then( + function success(_customers) { + var customers = { + pageSize: pageSize, + data: _customers.data, + nextPageLink: _customers.nextPageLink, + selection: null, + hasNext: _customers.hasNext, + pending: false + }; + if (customers.hasNext) { + customers.nextPageLink.limit = pageSize; + } + $mdDialog.show({ + controller: 'AssignEntityViewToCustomerController', + controllerAs: 'vm', + templateUrl: assignToCustomerTemplate, + locals: {entityViewIds: entityViewIds, customers: customers}, + parent: angular.element($document[0].body), + fullscreen: true, + targetEvent: $event + }).then(function () { + vm.grid.refreshList(); + }, function () { + }); + }, + function fail() { + }); + } + + function addEntityViewsToCustomer($event) { + if ($event) { + $event.stopPropagation(); + } + var pageSize = 10; + entityViewService.getTenantEntityViews({limit: pageSize, textSearch: ''}, false).then( + function success(_entityViews) { + var entityViews = { + pageSize: pageSize, + data: _entityViews.data, + nextPageLink: _entityViews.nextPageLink, + selections: {}, + selectedCount: 0, + hasNext: _entityViews.hasNext, + pending: false + }; + if (entityViews.hasNext) { + entityViews.nextPageLink.limit = pageSize; + } + $mdDialog.show({ + controller: 'AddEntityViewsToCustomerController', + controllerAs: 'vm', + templateUrl: addEntityViewsToCustomerTemplate, + locals: {customerId: customerId, entityViews: entityViews}, + parent: angular.element($document[0].body), + fullscreen: true, + targetEvent: $event + }).then(function () { + vm.grid.refreshList(); + }, function () { + }); + }, + function fail() { + }); + } + + function assignEntityViewsToCustomer($event, items) { + var entityViewIds = []; + for (var id in items.selections) { + entityViewIds.push(id); + } + assignToCustomer($event, entityViewIds); + } + + function unassignFromCustomer($event, entityView, isPublic) { + if ($event) { + $event.stopPropagation(); + } + var title; + var content; + var label; + if (isPublic) { + title = $translate.instant('entity-view.make-private-entity-view-title', {entityViewName: entityView.name}); + content = $translate.instant('entity-view.make-private-entity-view-text'); + label = $translate.instant('entity-view.make-private'); + } else { + title = $translate.instant('entity-view.unassign-entity-view-title', {entityViewName: entityView.name}); + content = $translate.instant('entity-view.unassign-entity-view-text'); + label = $translate.instant('entity-view.unassign-entity-view'); + } + var confirm = $mdDialog.confirm() + .targetEvent($event) + .title(title) + .htmlContent(content) + .ariaLabel(label) + .cancel($translate.instant('action.no')) + .ok($translate.instant('action.yes')); + $mdDialog.show(confirm).then(function () { + entityViewService.unassignEntityViewFromCustomer(entityView.id.id).then(function success() { + vm.grid.refreshList(); + }); + }); + } + + function unassignEntityViewsFromCustomer($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')) + .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.unassignEntityViewFromCustomer(id)); + } + $q.all(tasks).then(function () { + vm.grid.refreshList(); + }); + }); + } + + function makePublic($event, entityView) { + if ($event) { + $event.stopPropagation(); + } + var confirm = $mdDialog.confirm() + .targetEvent($event) + .title($translate.instant('entity-view.make-public-entity-view-title', {entityViewName: entityView.name})) + .htmlContent($translate.instant('entity-view.make-public-entity-view-text')) + .ariaLabel($translate.instant('entity-view.make-public')) + .cancel($translate.instant('action.no')) + .ok($translate.instant('action.yes')); + $mdDialog.show(confirm).then(function () { + entityViewService.makeEntityViewPublic(entityView.id.id).then(function success() { + vm.grid.refreshList(); + }); + }); + } +} diff --git a/ui/src/app/entity-view/entity-view.directive.js b/ui/src/app/entity-view/entity-view.directive.js new file mode 100644 index 0000000000..f98027062e --- /dev/null +++ b/ui/src/app/entity-view/entity-view.directive.js @@ -0,0 +1,67 @@ +/* + * 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. + */ +/* eslint-disable import/no-unresolved, import/default */ + +import entityViewFieldsetTemplate from './entity-view-fieldset.tpl.html'; + +/* eslint-enable import/no-unresolved, import/default */ + +/*@ngInject*/ +export default function EntityViewDirective($compile, $templateCache, toast, $translate, types, clipboardService, entityViewService, customerService) { + var linker = function (scope, element) { + var template = $templateCache.get(entityViewFieldsetTemplate); + element.html(template); + + scope.types = types; + scope.isAssignedToCustomer = false; + scope.assignedCustomer = null; + + scope.$watch('entityView', function(newVal) { + if (newVal) { + if (scope.entityView.customerId && scope.entityView.customerId.id !== types.id.nullUid) { + scope.isAssignedToCustomer = true; + customerService.getShortCustomerInfo(scope.entityView.customerId.id).then( + function success(customer) { + scope.assignedCustomer = customer; + } + ); + } else { + scope.isAssignedToCustomer = false; + scope.assignedCustomer = null; + } + } + }); + + scope.onEntityViewIdCopied = function() { + toast.showSuccess($translate.instant('entity-view.idCopiedMessage'), 750, angular.element(element).parent().parent(), 'bottom left'); + }; + + $compile(element.contents())(scope); + } + return { + restrict: "E", + link: linker, + scope: { + entityView: '=', + isEdit: '=', + entityViewScope: '=', + theForm: '=', + onAssignToCustomer: '&', + onUnassignFromCustomer: '&', + onDeleteEntityView: '&' + } + }; +} diff --git a/ui/src/app/entity-view/entity-view.routes.js b/ui/src/app/entity-view/entity-view.routes.js new file mode 100644 index 0000000000..14f5079d41 --- /dev/null +++ b/ui/src/app/entity-view/entity-view.routes.js @@ -0,0 +1,72 @@ +/* + * 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. + */ +/* eslint-disable import/no-unresolved, import/default */ + +import entityViewsTemplate from './entity-views.tpl.html'; + +/* eslint-enable import/no-unresolved, import/default */ + +/*@ngInject*/ +export default function EntityViewRoutes($stateProvider, types) { + $stateProvider + .state('home.entityViews', { + url: '/entityViews', + params: {'topIndex': 0}, + module: 'private', + auth: ['TENANT_ADMIN', 'CUSTOMER_USER'], + views: { + "content@home": { + templateUrl: entityViewsTemplate, + controller: 'EntityViewController', + controllerAs: 'vm' + } + }, + data: { + entityViewsTypes: 'tenant', + searchEnabled: true, + searchByEntitySubtype: true, + searchEntityType: types.entityType.entityview, + pageTitle: 'entity-views.entity-views' + }, + ncyBreadcrumb: { + label: '{"icon": "devices_other", "label": "entity-view.entity-views"}' + } + }) + .state('home.customers.entityViews', { + url: '/:customerId/entityViews', + params: {'topIndex': 0}, + module: 'private', + auth: ['TENANT_ADMIN'], + views: { + "content@home": { + templateUrl: entityViewsTemplate, + controllerAs: 'vm', + controller: 'EntityViewController' + } + }, + data: { + entityViewsTypes: 'customer', + searchEnabled: true, + searchByEntitySubtype: true, + searchEntityType: types.entityType.entityview, + pageTitle: 'customer.entity-views' + }, + ncyBreadcrumb: { + label: '{"icon": "devices_other", "label": "{{ vm.customerEntityViewsTitle }}", "translate": "false"}' + } + }); + +} diff --git a/ui/src/app/entity-view/entity-views.tpl.html b/ui/src/app/entity-view/entity-views.tpl.html new file mode 100644 index 0000000000..5398449273 --- /dev/null +++ b/ui/src/app/entity-view/entity-views.tpl.html @@ -0,0 +1,83 @@ + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/ui/src/app/entity-view/index.js b/ui/src/app/entity-view/index.js new file mode 100644 index 0000000000..ebdd3ea282 --- /dev/null +++ b/ui/src/app/entity-view/index.js @@ -0,0 +1,41 @@ +/* + * 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. + */ +import uiRouter from 'angular-ui-router'; +import thingsboardGrid from '../components/grid.directive'; +import thingsboardApiUser from '../api/user.service'; +import thingsboardApiEntityView from '../api/entity-view.service'; +import thingsboardApiCustomer from '../api/customer.service'; + +import EntityViewRoutes from './entity-view.routes'; +import EntityViewCardController from './entity-view.controller'; +import AssignEntityViewToCustomerController from './assign-to-customer.controller'; +import AddEntityViewsToCustomerController from './add-entity-views-to-customer.controller'; +import EntityViewDirective from './entity-view.directive'; + +export default angular.module('thingsboard.entityView', [ + uiRouter, + thingsboardGrid, + thingsboardApiUser, + thingsboardApiEntityView, + thingsboardApiCustomer +]) + .config(EntityViewRoutes) + .controller('EntityViewController', EntityViewCardController) + .controller('EntityViewCardController', EntityViewCardController) + .controller('AssignEntityViewToCustomerController', AssignEntityViewToCustomerController) + .controller('AddEntityViewsToCustomerController', AddEntityViewsToCustomerController) + .directive('tbEntityView', EntityViewDirective) + .name; diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json index 6321d63f46..5e04a52a00 100644 --- a/ui/src/app/locale/locale.constant-en_US.json +++ b/ui/src/app/locale/locale.constant-en_US.json @@ -338,10 +338,12 @@ "dashboard": "Customer Dashboard", "dashboards": "Customer Dashboards", "devices": "Customer Devices", + "entity-views": "Customer Entity Views", "assets": "Customer Assets", "public-dashboards": "Public Dashboards", "public-devices": "Public Devices", "public-assets": "Public Assets", + "public-entity-views": "Public Entity Views", "add": "Add Customer", "delete": "Delete customer", "manage-customer-users": "Manage customer users", @@ -750,6 +752,77 @@ "no-entities-prompt": "No entities found", "no-data": "No data to display" }, + "entity-view": { + "entity-view": "Entity View", + "entity-views": "Entity Views", + "management": "Entity View management", + "view-entity-views": "View Entity Views", + "entity-view-alias": "Entity View alias", + "aliases": "Entity View aliases", + "no-alias-matching": "'{{alias}}' not found.", + "no-aliases-found": "No aliases found.", + "no-key-matching": "'{{key}}' not found.", + "no-keys-found": "No keys found.", + "create-new-alias": "Create a new one!", + "create-new-key": "Create a new one!", + "duplicate-alias-error": "Duplicate alias found '{{alias}}'.
Entity View aliases must be unique whithin the dashboard.", + "configure-alias": "Configure '{{alias}}' alias", + "no-entity-views-matching": "No entity views matching '{{entity}}' were found.", + "alias": "Alias", + "alias-required": "Entity View alias is required.", + "remove-alias": "Remove entity view alias", + "add-alias": "Add entity view alias", + "name-starts-with": "Entity View name starts with", + "entity-view-list": "Entity View list", + "use-entity-view-name-filter": "Use filter", + "entity-view-list-empty": "No entity views selected.", + "entity-view-name-filter-required": "Entity view name filter is required.", + "entity-view-name-filter-no-entity-view-matched": "No entity views starting with '{{entityView}}' were found.", + "add": "Add Entity View", + "assign-to-customer": "Assign to customer", + "assign-entity-view-to-customer": "Assign Entity View(s) To Customer", + "assign-entity-view-to-customer-text": "Please select the entity views to assign to the customer", + "no-entity-views-text": "No entity views found", + "assign-to-customer-text": "Please select the customer to assign the entity view(s)", + "entity-view-details": "Entity view details", + "add-entity-view-text": "Add new entity view", + "delete": "Delete entity view", + "assign-entity-views": "Assign entity views", + "assign-entity-views-text": "Assign { count, plural, 1 {1 entityView} other {# entityViews} } to customer", + "delete-entity-views": "Delete entity views", + "unassign-from-customer": "Unassign from customer", + "unassign-entity-views": "Unassign entity views", + "unassign-entity-views-action-title": "Unassign { count, plural, 1 {1 entityView} other {# entityViews} } from customer", + "assign-new-entity-view": "Assign new entity view", + "delete-entity-view-title": "Are you sure you want to delete the entity view '{{entityViewName}}'?", + "delete-entity-view-text": "Be careful, after the confirmation the entity view and all related data will become unrecoverable.", + "delete-entity-views-title": "Are you sure you want to entity view { count, plural, 1 {1 entityView} other {# entityViews} }?", + "delete-entity-views-action-title": "Delete { count, plural, 1 {1 entityView} other {# entityViews} }", + "delete-entity-views-text": "Be careful, after the confirmation all selected entity views will be removed and all related data will become unrecoverable.", + "unassign-entity-view-title": "Are you sure you want to unassign the entity view '{{entityViewName}}'?", + "unassign-entity-view-text": "After the confirmation the entity view will be unassigned and won't be accessible by the customer.", + "unassign-entity-view": "Unassign entity view", + "unassign-entity-views-title": "Are you sure you want to unassign { count, plural, 1 {1 entityView} other {# entityViews} }?", + "unassign-entity-views-text": "After the confirmation all selected entity views will be unassigned and won't be accessible by the customer.", + "entity-view-type": "Entity View type", + "entity-view-type-required": "Entity View type is required.", + "select-entity-view-type": "Select entity view type", + "enter-entity-view-type": "Enter entity view type", + "any-entity-view": "Any entity view", + "no-entity-view-types-matching": "No entity view types matching '{{entitySubtype}}' were found.", + "entity-view-type-list-empty": "No entity view types selected.", + "entity-view-types": "Entity View types", + "name": "Name", + "name-required": "Name is required.", + "description": "Description", + "events": "Events", + "details": "Details", + "copyId": "Copy entity view Id", + "assignedToCustomer": "Assigned to customer", + "unable-entity-view-device-alias-title": "Unable to delete entity view alias", + "unable-entity-view-device-alias-text": "Device alias '{{entityViewAlias}}' can't be deleted as it used by the following widget(s):
{{widgetsList}}", + "select-entity-view": "Select entity view" + }, "event": { "event-type": "Event type", "type-error": "Error", From c5827e1b9e0f08db4756ca28f40bde4180837f6b Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Thu, 6 Sep 2018 13:07:31 +0300 Subject: [PATCH 049/118] was added entity_type field to entity_views table --- application/src/main/data/upgrade/2.1.1/schema_update.cql | 3 ++- dao/src/main/resources/cassandra/schema.cql | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) 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 d9ba517df7..1329a0b546 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/dao/src/main/resources/cassandra/schema.cql b/dao/src/main/resources/cassandra/schema.cql index bdd413d6ad..68f196f005 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, From e132d702a2ec05e688eddacad5d5188ec8ca3450 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Thu, 6 Sep 2018 13:10:48 +0300 Subject: [PATCH 050/118] Was changed path to all sql and nosql tests --- .../thingsboard/server/controller/ControllerSqlTestSuite.java | 2 +- .../server/controller/nosql/EntityViewControllerNoSqlTest.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) 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 a9e94e9184..c8a5da8151 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 ad066fc7ab..404e4e253f 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 { } From 3a3f6636e11f6fac0152b8621bb6afb3bb668001 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Thu, 6 Sep 2018 13:13:44 +0300 Subject: [PATCH 051/118] Was added new field to entity and method save to dao interface --- .../entityview/CassandraEntityViewDao.java | 90 +++++++++++++++++++ .../server/dao/entityview/EntityViewDao.java | 8 ++ .../dao/model/nosql/EntityViewEntity.java | 42 +++++---- 3 files changed, 123 insertions(+), 17 deletions(-) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java 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 0000000000..e9282e23b0 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java @@ -0,0 +1,90 @@ +/** + * 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 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.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.List; +import java.util.Optional; +import java.util.UUID; + +import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_TABLE_FAMILY_NAME; + +/** + * Created by Victor Basanets on 9/06/2017. + */ +@Component +@Slf4j +@NoSqlDao +public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao implements EntityViewDao { + + @Override + protected Class 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; + } + + /*Wasn't done!!!*/ + @Override + public List findEntityViewByTenantId(UUID tenantId, TextPageLink pageLink) { + + } + + @Override + public Optional findEntityViewByTenantIdAndName(UUID tenantId, String name) { + return Optional.empty(); + } + + @Override + public List findEntityViewByTenantIdAndEntityId(UUID tenantId, UUID entityId, TextPageLink pageLink) { + return null; + } + + @Override + public List findEntityViewsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) { + return null; + } + + @Override + public List 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 25404db834..5cbbef834f 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 @@ -29,6 +29,14 @@ import java.util.UUID; */ public interface EntityViewDao extends Dao { + /** + * 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. * 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 65914dd566..075a2c5854 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 { @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 { @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 { @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 { } if (entityView.getEntityId() != null) { this.entityId = entityView.getEntityId().getId(); + this.entityType = entityView.getEntityId().getEntityType(); } if (entityView.getTenantId() != null) { this.tenantId = entityView.getTenantId().getId(); @@ -103,11 +111,11 @@ public class EntityViewEntity implements SearchTextEntity { this.customerId = entityView.getCustomerId().getId(); } this.name = entityView.getName(); -// try { -// this.keys = entityView.getKeys(); -// } catch (IOException e) { -// e.printStackTrace(); -// } + try { + this.keys = mapper.writeValueAsString(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"; this.searchText = entityView.getSearchText(); @@ -124,7 +132,7 @@ public class EntityViewEntity implements SearchTextEntity { 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,11 +141,11 @@ public class EntityViewEntity implements SearchTextEntity { entityView.setCustomerId(new CustomerId(customerId)); } entityView.setName(name); -// try { -// entityView.setKeys((TelemetryEntityView) entityView.getKeys().toObject(keys)); -// } catch (IOException e) { -// e.printStackTrace(); -// } + try { + entityView.setKeys(mapper.readValue(keys, TelemetryEntityView.class)); + } catch (IOException e) { + e.printStackTrace(); + } entityView.setTsBegin(Long.parseLong(tsBegin)); entityView.setTsEnd(Long.parseLong(tsEnd)); entityView.setAdditionalInfo(additionalInfo); From 80c2721d1d46cd77e4cf391a543dc72ff1cd6f89 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Thu, 6 Sep 2018 14:18:06 +0300 Subject: [PATCH 052/118] Was added the findEntityViewByIdAsync method --- .../server/dao/entityview/EntityViewService.java | 8 ++++---- .../server/dao/entityview/EntityViewServiceImpl.java | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) 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 943d35e9b4..6de86be60c 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 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 6554083fe4..6de1043794 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,6 +15,7 @@ */ 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; @@ -190,6 +191,13 @@ public class EntityViewServiceImpl extends AbstractEntityService new CustomerEntityViewsUnAssigner(tenantId).removeEntities(customerId); } + @Override + public ListenableFuture findEntityViewByIdAsync(EntityViewId entityViewId) { + log.trace("Executing findDeviceById [{}]", entityViewId); + validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); + return entityViewDao.findByIdAsync(entityViewId.getId()); + } + private DataValidator entityViewValidator = new DataValidator() { From 61da5d5d6e17685c3a57cacc07b693ca1a4adcb8 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Thu, 6 Sep 2018 14:19:35 +0300 Subject: [PATCH 053/118] Was addet to validate instance of entity-view --- .../service/security/AccessValidator.java | 39 +++++++++++++++---- 1 file changed, 31 insertions(+), 8 deletions(-) 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 600820ec73..7f4f23a0ef 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 callback) { + if (currentUser.isSystemAdmin()) { + callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION)); + } else { + ListenableFuture 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 FutureCallback getCallback(FutureCallback callback, Function> transformer) { return new FutureCallback() { @Override From ae647024a5e53dab6962cb571914b32cb74b6890 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Fri, 7 Sep 2018 17:34:44 +0300 Subject: [PATCH 054/118] Was refactored --- .../java/org/thingsboard/server/common/data/EntityView.java | 4 ++-- .../server/common/data/objects/AttributesEntityView.java | 5 ----- .../server/common/data/objects/TelemetryEntityView.java | 5 ----- 3 files changed, 2 insertions(+), 12 deletions(-) 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 813a9acd08..49dd20959f 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 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 b1d270c934..1c32579b72 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 e7398e6500..c899c65590 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 + '}'; - } } From 842240671d4dbb9d77dd83f07c78280ff1522f18 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Fri, 7 Sep 2018 17:36:52 +0300 Subject: [PATCH 055/118] Was added async method --- .../server/dao/entityview/EntityViewServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 6de1043794..49e1618c73 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 @@ -193,7 +193,7 @@ public class EntityViewServiceImpl extends AbstractEntityService @Override public ListenableFuture findEntityViewByIdAsync(EntityViewId entityViewId) { - log.trace("Executing findDeviceById [{}]", entityViewId); + log.trace("Executing findEntityViewById [{}]", entityViewId); validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); return entityViewDao.findByIdAsync(entityViewId.getId()); } From ad48ecabd84f961ebaeefe385d94966077d9a1c4 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Fri, 7 Sep 2018 17:38:54 +0300 Subject: [PATCH 056/118] Was added some of the entity-view constants and refactored code --- .../org/thingsboard/server/dao/model/ModelConstants.java | 4 ++-- .../server/dao/model/nosql/EntityViewEntity.java | 8 ++++---- .../server/dao/model/sql/EntityViewEntity.java | 9 ++++----- 3 files changed, 10 insertions(+), 11 deletions(-) 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 d06ddbd8e5..6932bea1a3 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 075a2c5854..bb5abdd87f 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 @@ -116,8 +116,8 @@ public class EntityViewEntity implements SearchTextEntity { } 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() != null ? String.valueOf(entityView.getStartTs()) : "0"; + this.tsEnd = entityView.getEndTs() != null ? String.valueOf(entityView.getEndTs()) : "0"; this.searchText = entityView.getSearchText(); this.additionalInfo = entityView.getAdditionalInfo(); } @@ -146,8 +146,8 @@ public class EntityViewEntity implements SearchTextEntity { } 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/model/sql/EntityViewEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityViewEntity.java index 9136717fe3..c81e8f6027 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 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() != null ? String.valueOf(entityView.getStartTs()) : "0"; + this.tsEnd = entityView.getEndTs() != null ? String.valueOf(entityView.getEndTs()) : "0"; this.searchText = entityView.getSearchText(); this.additionalInfo = entityView.getAdditionalInfo(); } @@ -142,8 +141,8 @@ public class EntityViewEntity extends BaseSqlEntity 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; } From 66b330280ebe114d8ebe75f61aaa4a9da4f7e622 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Fri, 7 Sep 2018 17:46:56 +0300 Subject: [PATCH 057/118] Was added checks on entity-views obj fiew method for fetch update queries startTs & entdTs and other --- .../dao/timeseries/BaseTimeseriesService.java | 86 +++++++++++++++++-- 1 file changed, 81 insertions(+), 5 deletions(-) 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 c981378939..634d7f222e 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 @@ -1,12 +1,12 @@ /** * 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 - * + *

+ * 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. @@ -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> findAll(EntityId entityId, List 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> 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 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> 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> save(EntityId entityId, List tsKvEntries, long ttl) { + try { + checkForNonEntityView(entityId); + } catch (Exception e) { + e.printStackTrace(); + } List> 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> 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 updateQueriesForEntityView(EntityView entityView, List queries) { + List 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 chooseKeysForEntityView(EntityView entityView, Collection keys) { + Collection 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"); + } + } } From 457b5d1250d2b71f49cb07ad49a3c2f13d369457 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Fri, 7 Sep 2018 17:58:09 +0300 Subject: [PATCH 058/118] Created entity-view dao for nosql db --- .../entityview/CassandraEntityViewDao.java | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) 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 e9282e23b0..5716460d20 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 @@ -16,22 +16,24 @@ 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.List; -import java.util.Optional; -import java.util.UUID; +import java.util.*; -import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_TABLE_FAMILY_NAME; +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. @@ -62,20 +64,36 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao findEntityViewByTenantId(UUID tenantId, TextPageLink pageLink) { + log.debug("Try to find entity-views by tenantId [{}] and pageLink [{}]", tenantId, pageLink); + List 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 findEntityViewByTenantIdAndName(UUID tenantId, String name) { - return Optional.empty(); + public Optional 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 findEntityViewByTenantIdAndEntityId(UUID tenantId, UUID entityId, TextPageLink pageLink) { - return null; + log.debug("Try to find entity-views by tenantId [{}], entityId[{}] and pageLink [{}]", tenantId, entityId, pageLink); + List 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 From e0c2c5a994ae43b2f9ec94c788df3db8cb09790e Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Fri, 7 Sep 2018 18:38:25 +0300 Subject: [PATCH 059/118] Was added caching --- .../dao/entityview/EntityViewServiceImpl.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) 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 49e1618c73..31d3b30518 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 @@ -21,6 +21,8 @@ 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; @@ -41,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; @@ -68,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); @@ -83,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); @@ -107,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 list = new ArrayList<>(); list.add(entityView.getTenantId()); list.add(entityView.getName()); + cache.evict(list); entityViewDao.removeById(entityViewId.getId()); } @@ -125,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 findEntityViewByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, TextPageLink pageLink) { @@ -164,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 findEntityViewsByTenantIdAndCustomerIdAndEntityId(TenantId tenantId, CustomerId customerId, From 20f4782cae1ae9f64fb4cd063e3aff1cf08cda9d Mon Sep 17 00:00:00 2001 From: Viktor Basanets Date: Mon, 10 Sep 2018 00:15:14 +0300 Subject: [PATCH 060/118] Was replaced header --- .../server/dao/timeseries/BaseTimeseriesService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 634d7f222e..9b837b24a5 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 @@ -1,12 +1,12 @@ /** * 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 - *

+ * + * 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. From ae8d8f01c713bf2db3a98e38709bef1805055009 Mon Sep 17 00:00:00 2001 From: Viktor Basanets Date: Mon, 10 Sep 2018 00:16:31 +0300 Subject: [PATCH 061/118] Was replaced null to 0L --- .../thingsboard/server/dao/model/nosql/EntityViewEntity.java | 4 ++-- .../thingsboard/server/dao/model/sql/EntityViewEntity.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) 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 bb5abdd87f..990ff704c3 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 @@ -116,8 +116,8 @@ public class EntityViewEntity implements SearchTextEntity { } catch (IOException e) { e.printStackTrace(); } - this.tsBegin = entityView.getStartTs() != null ? String.valueOf(entityView.getStartTs()) : "0"; - this.tsEnd = entityView.getEndTs() != null ? String.valueOf(entityView.getEndTs()) : "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(); } 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 c81e8f6027..a89d3dec84 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 @@ -105,8 +105,8 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc } catch (IOException e) { e.printStackTrace(); } - this.tsBegin = entityView.getStartTs() != null ? String.valueOf(entityView.getStartTs()) : "0"; - this.tsEnd = entityView.getEndTs() != null ? String.valueOf(entityView.getEndTs()) : "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(); } From 5bf9528ee8878f80dbe5dadf6787a9086208779c Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Mon, 10 Sep 2018 11:11:07 +0300 Subject: [PATCH 062/118] Fixes for entity view --- .../controller/EntityViewController.java | 52 +++++++++++++++++-- .../entityview/EntityViewSearchQuery.java | 42 +++++++++++++++ .../server/dao/entityview/EntityViewDao.java | 2 - .../dao/entityview/EntityViewService.java | 8 +++ .../dao/entityview/EntityViewServiceImpl.java | 43 ++++++++++++--- .../server/dao/model/ModelConstants.java | 1 + .../dao/model/nosql/EntityViewEntity.java | 14 +++-- .../dao/sql/entityview/JpaEntityViewDao.java | 6 +++ dao/src/main/resources/cassandra/schema.cql | 2 +- ui/src/app/api/entity-view.service.js | 4 ++ ui/src/app/common/types.constant.js | 2 +- .../entity-view/entity-view-fieldset.tpl.html | 10 ++-- .../app/entity-view/entity-view.controller.js | 12 ++--- .../app/entity-view/entity-view.directive.js | 4 ++ ui/src/app/entity-view/entity-view.routes.js | 10 ++-- ui/src/app/entity-view/entity-views.tpl.html | 20 +++---- ui/src/app/entity-view/index.js | 4 +- ui/src/app/layout/index.js | 2 + ui/src/app/locale/locale.constant-en_US.json | 3 +- ui/src/app/services/menu.service.js | 52 +++++++++++++++---- 20 files changed, 226 insertions(+), 67 deletions(-) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/entityview/EntityViewSearchQuery.java 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 fd3ccf2fe1..227bed01f3 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java @@ -19,17 +19,21 @@ import com.google.common.util.concurrent.ListenableFuture; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; +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.audit.ActionType; +import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; import org.thingsboard.server.common.data.exception.ThingsboardException; -import org.thingsboard.server.common.data.id.CustomerId; 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.service.security.model.SecurityUser; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; /** * Created by Victor Basanets on 8/28/2017. @@ -41,7 +45,7 @@ public class EntityViewController extends BaseController { public static final String ENTITY_VIEW_ID = "entityViewId"; @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/entity-view/{entityViewId}", method = RequestMethod.GET) + @RequestMapping(value = "/entityView/{entityViewId}", method = RequestMethod.GET) @ResponseBody public EntityView getEntityViewById(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { @@ -56,7 +60,7 @@ public class EntityViewController extends BaseController { } @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/entity-view", method = RequestMethod.POST) + @RequestMapping(value = "/entityView", method = RequestMethod.POST) @ResponseBody public EntityView saveEntityView(@RequestBody EntityView entityView) throws ThingsboardException { try { @@ -76,7 +80,7 @@ public class EntityViewController extends BaseController { } @PreAuthorize("hasAuthority('TENANT_ADMIN')") - @RequestMapping(value = "/entity-view/{entityViewId}", method = RequestMethod.DELETE) + @RequestMapping(value = "/entityView/{entityViewId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) public void deleteEntityView(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { checkParameter(ENTITY_VIEW_ID, strEntityViewId); @@ -95,4 +99,44 @@ public class EntityViewController extends BaseController { throw handleException(e); } } + + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/tenant/entityViews", params = {"limit"}, method = RequestMethod.GET) + @ResponseBody + public TextPageData getTenantEntityViews( + @RequestParam int limit, + @RequestParam(required = false) String textSearch, + @RequestParam(required = false) String idOffset, + @RequestParam(required = false) String textOffset) throws ThingsboardException { + try { + TenantId tenantId = getCurrentUser().getTenantId(); + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); + return checkNotNull(entityViewService.findEntityViewByTenantId(tenantId, pageLink)); + } catch (Exception e) { + throw handleException(e); + } + } + + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/entityViews", method = RequestMethod.POST) + @ResponseBody + public List findByQuery(@RequestBody EntityViewSearchQuery query) throws ThingsboardException { + checkNotNull(query); + checkNotNull(query.getParameters()); + checkEntityId(query.getParameters().getEntityId()); + try { + List entityViews = checkNotNull(entityViewService.findEntityViewsByQuery(query).get()); + entityViews = entityViews.stream().filter(entityView -> { + try { + checkEntityView(entityView); + return true; + } catch (ThingsboardException e) { + return false; + } + }).collect(Collectors.toList()); + return entityViews; + } catch (Exception e) { + throw handleException(e); + } + } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/entityview/EntityViewSearchQuery.java b/common/data/src/main/java/org/thingsboard/server/common/data/entityview/EntityViewSearchQuery.java new file mode 100644 index 0000000000..752eafc6ad --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/entityview/EntityViewSearchQuery.java @@ -0,0 +1,42 @@ +/** + * 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.common.data.entityview; + +import lombok.Data; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.EntityRelationsQuery; +import org.thingsboard.server.common.data.relation.EntityTypeFilter; +import org.thingsboard.server.common.data.relation.RelationsSearchParameters; + +import java.util.Collections; +import java.util.List; + +@Data +public class EntityViewSearchQuery { + + private RelationsSearchParameters parameters; + private String relationType; + + public EntityRelationsQuery toEntitySearchQuery() { + EntityRelationsQuery query = new EntityRelationsQuery(); + query.setParameters(parameters); + query.setFilters( + Collections.singletonList(new EntityTypeFilter(relationType == null ? EntityRelation.CONTAINS_TYPE : relationType, + Collections.singletonList(EntityType.ENTITY_VIEW)))); + return query; + } +} 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 5cbbef834f..56a688ae47 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 @@ -16,7 +16,6 @@ package org.thingsboard.server.dao.entityview; import org.thingsboard.server.common.data.EntityView; -import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.dao.Dao; @@ -92,5 +91,4 @@ public interface EntityViewDao extends Dao { UUID customerId, UUID entityId, TextPageLink pageLink); - } 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 6de86be60c..a60376e501 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 @@ -16,12 +16,18 @@ package org.thingsboard.server.dao.entityview; import com.google.common.util.concurrent.ListenableFuture; +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.device.DeviceSearchQuery; +import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; import org.thingsboard.server.common.data.id.*; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; +import java.util.List; + /** * Created by Victor Basanets on 8/27/2017. */ @@ -57,4 +63,6 @@ public interface EntityViewService { void unassignCustomerEntityViews(TenantId tenantId, CustomerId customerId); ListenableFuture findEntityViewByIdAsync(EntityViewId entityViewId); + + ListenableFuture> findEntityViewsByQuery(EntityViewSearchQuery query); } 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 31d3b30518..2551183dcf 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,6 +15,8 @@ */ package org.thingsboard.server.dao.entityview; +import com.google.common.base.Function; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -25,14 +27,22 @@ 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.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.device.DeviceSearchQuery; +import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; 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.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.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.dao.customer.CustomerDao; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; @@ -40,8 +50,12 @@ import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.tenant.TenantDao; +import javax.annotation.Nullable; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; +import java.util.stream.Collectors; import static org.thingsboard.server.common.data.CacheConstants.DEVICE_CACHE; import static org.thingsboard.server.common.data.CacheConstants.ENTITY_VIEW_CACHE; @@ -55,8 +69,7 @@ import static org.thingsboard.server.dao.service.Validator.validateString; */ @Service @Slf4j -public class EntityViewServiceImpl extends AbstractEntityService - implements EntityViewService { +public class EntityViewServiceImpl extends AbstractEntityService implements EntityViewService { public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; public static final String INCORRECT_PAGE_LINK = "Incorrect page link "; @@ -75,7 +88,7 @@ public class EntityViewServiceImpl extends AbstractEntityService @Autowired private CacheManager cacheManager; - @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}") +// @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}") @Override public EntityView findEntityViewById(EntityViewId entityViewId) { log.trace("Executing findEntityViewById [{}]", entityViewId); @@ -91,7 +104,7 @@ public class EntityViewServiceImpl extends AbstractEntityService .orElse(null); } - @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityView.id}") +// @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityView.id}") @Override public EntityView saveEntityView(EntityView entityView) { log.trace("Executing save entity view [{}]", entityView); @@ -136,7 +149,7 @@ public class EntityViewServiceImpl extends AbstractEntityService return new TextPageData<>(entityViews, pageLink); } - @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #entityId, #pageLink}") +// @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #entityId, #pageLink}") @Override public TextPageData findEntityViewByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, TextPageLink pageLink) { @@ -176,7 +189,7 @@ public class EntityViewServiceImpl extends AbstractEntityService return new TextPageData<>(entityViews, pageLink); } - @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #customerId, #entityId, #pageLink}") +// @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #customerId, #entityId, #pageLink}") @Override public TextPageData findEntityViewsByTenantIdAndCustomerIdAndEntityId(TenantId tenantId, CustomerId customerId, @@ -211,6 +224,24 @@ public class EntityViewServiceImpl extends AbstractEntityService return entityViewDao.findByIdAsync(entityViewId.getId()); } + @Override + public ListenableFuture> findEntityViewsByQuery(EntityViewSearchQuery query) { + ListenableFuture> relations = relationService.findByQuery(query.toEntitySearchQuery()); + ListenableFuture> entityViews = Futures.transformAsync(relations, r -> { + EntitySearchDirection direction = query.toEntitySearchQuery().getParameters().getDirection(); + List> futures = new ArrayList<>(); + for (EntityRelation relation : r) { + EntityId entityId = direction == EntitySearchDirection.FROM ? relation.getTo() : relation.getFrom(); + if (entityId.getEntityType() == EntityType.ENTITY_VIEW) { + futures.add(findEntityViewByIdAsync(new EntityViewId(entityId.getId()))); + } + } + return Futures.successfulAsList(futures); + }); + + return entityViews; + } + private DataValidator entityViewValidator = new DataValidator() { 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 6932bea1a3..a96f258043 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 @@ -151,6 +151,7 @@ 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 = DEVICE_TYPE_PROPERTY; 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"; 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 990ff704c3..3f7571363a 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 @@ -16,6 +16,7 @@ package org.thingsboard.server.dao.model.nosql; import com.datastax.driver.core.utils.UUIDs; +import com.datastax.driver.mapping.annotations.Column; import com.datastax.driver.mapping.annotations.PartitionKey; import com.datastax.driver.mapping.annotations.Table; import com.fasterxml.jackson.databind.JsonNode; @@ -31,10 +32,8 @@ 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; @@ -55,22 +54,21 @@ public class EntityViewEntity implements SearchTextEntity { @Column(name = ID_PROPERTY) private UUID id; - @PartitionKey(value = 1) - @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) + @PartitionKey(value = 1) @Column(name = ModelConstants.ENTITY_VIEW_TENANT_ID_PROPERTY) private UUID tenantId; - @PartitionKey(value = 3) + @PartitionKey(value = 2) @Column(name = ModelConstants.ENTITY_VIEW_CUSTOMER_ID_PROPERTY) private UUID customerId; + @Column(name = ModelConstants.ENTITY_VIEW_ENTITY_ID_PROPERTY) + private UUID entityId; + @Column(name = ModelConstants.ENTITY_VIEW_NAME_PROPERTY) private String name; 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 57b0afae8b..6ef0acba7e 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,12 +15,16 @@ */ package org.thingsboard.server.dao.sql.entityview; +import com.google.common.util.concurrent.ListenableFuture; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.PageRequest; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.EntitySubtype; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.entityview.EntityViewDao; @@ -28,6 +32,8 @@ import org.thingsboard.server.dao.model.sql.EntityViewEntity; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; import org.thingsboard.server.dao.util.SqlDao; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; diff --git a/dao/src/main/resources/cassandra/schema.cql b/dao/src/main/resources/cassandra/schema.cql index 68f196f005..89df266d75 100644 --- a/dao/src/main/resources/cassandra/schema.cql +++ b/dao/src/main/resources/cassandra/schema.cql @@ -651,7 +651,7 @@ CREATE TABLE IF NOT EXISTS thingsboard.entity_views ( ts_end bigint, search_text text, additional_info text, - PRIMARY KEY (id, entity_id, tenant_id, customer_id) + PRIMARY KEY (id, tenant_id, customer_id) ); CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_name AS diff --git a/ui/src/app/api/entity-view.service.js b/ui/src/app/api/entity-view.service.js index 9bd8f8db08..f2d190863e 100644 --- a/ui/src/app/api/entity-view.service.js +++ b/ui/src/app/api/entity-view.service.js @@ -155,6 +155,10 @@ function EntityViewService($http, $q, $window, userService, attributeService, cu function saveEntityView(entityView) { var deferred = $q.defer(); var url = '/api/entityView'; + + entityView.keys = {}; + entityView.keys.timeseries = ['a', 'b']; + $http.post(url, entityView).then(function success(response) { deferred.resolve(response.data); }, function fail() { diff --git a/ui/src/app/common/types.constant.js b/ui/src/app/common/types.constant.js index 1d1b7171c3..060b557b5d 100644 --- a/ui/src/app/common/types.constant.js +++ b/ui/src/app/common/types.constant.js @@ -328,7 +328,7 @@ export default angular.module('thingsboard.types', []) alarm: "ALARM", rulechain: "RULE_CHAIN", rulenode: "RULE_NODE", - entityview: "ENTITY_VIEW" + entityView: "ENTITY_VIEW" }, aliasEntityType: { current_customer: "CURRENT_CUSTOMER" diff --git a/ui/src/app/entity-view/entity-view-fieldset.tpl.html b/ui/src/app/entity-view/entity-view-fieldset.tpl.html index e0000c6d9d..cb46f3ddf7 100644 --- a/ui/src/app/entity-view/entity-view-fieldset.tpl.html +++ b/ui/src/app/entity-view/entity-view-fieldset.tpl.html @@ -15,6 +15,9 @@ limitations under the License. --> +{{ 'entity-view.make-public' | translate }} {{ 'entity-view.assign-to-customer' | translate }} @@ -49,13 +52,6 @@

entity-view.name-required
- - diff --git a/ui/src/app/entity-view/entity-view.controller.js b/ui/src/app/entity-view/entity-view.controller.js index fd3b5a836a..2c8c8ea036 100644 --- a/ui/src/app/entity-view/entity-view.controller.js +++ b/ui/src/app/entity-view/entity-view.controller.js @@ -194,7 +194,7 @@ export function EntityViewController($rootScope, userService, entityViewService, entityViewGroupActionsList.push( { onAction: function ($event, items) { - assignEntiyViewsToCustomer($event, items); + assignEntityViewsToCustomer($event, items); }, name: function() { return $translate.instant('entity-view.assign-entity-views') }, details: function(selectedCount) { @@ -221,10 +221,10 @@ export function EntityViewController($rootScope, userService, entityViewService, fetchEntityViewsFunction = function (pageLink, entityViewType) { return entityViewService.getCustomerEntityViews(customerId, pageLink, true, null, entityViewType); }; - deleteentityViewFunction = function (entityViewId) { + deleteEntityViewFunction = function (entityViewId) { return entityViewService.unassignEntityViewFromCustomer(entityViewId); }; - refreshentityViewsParamsFunction = function () { + refreshEntityViewsParamsFunction = function () { return {"customerId": customerId, "topIndex": vm.topIndex}; }; @@ -271,9 +271,9 @@ export function EntityViewController($rootScope, userService, entityViewService, } } - vm.entityViewGridConfig.refreshParamsFunc = refreshentityViewsParamsFunction; - vm.entityViewGridConfig.fetchItemsFunc = fetchentityViewsFunction; - vm.entityViewGridConfig.deleteItemFunc = deleteentityViewFunction; + vm.entityViewGridConfig.refreshParamsFunc = refreshEntityViewsParamsFunction; + vm.entityViewGridConfig.fetchItemsFunc = fetchEntityViewsFunction; + vm.entityViewGridConfig.deleteItemFunc = deleteEntityViewFunction; } diff --git a/ui/src/app/entity-view/entity-view.directive.js b/ui/src/app/entity-view/entity-view.directive.js index f98027062e..5a3d8765a3 100644 --- a/ui/src/app/entity-view/entity-view.directive.js +++ b/ui/src/app/entity-view/entity-view.directive.js @@ -27,6 +27,7 @@ export default function EntityViewDirective($compile, $templateCache, toast, $tr scope.types = types; scope.isAssignedToCustomer = false; + scope.isPublic = false; scope.assignedCustomer = null; scope.$watch('entityView', function(newVal) { @@ -36,10 +37,12 @@ export default function EntityViewDirective($compile, $templateCache, toast, $tr customerService.getShortCustomerInfo(scope.entityView.customerId.id).then( function success(customer) { scope.assignedCustomer = customer; + scope.isPublic = customer.isPublic; } ); } else { scope.isAssignedToCustomer = false; + scope.isPublic = false; scope.assignedCustomer = null; } } @@ -60,6 +63,7 @@ export default function EntityViewDirective($compile, $templateCache, toast, $tr entityViewScope: '=', theForm: '=', onAssignToCustomer: '&', + onMakePublic: '&', onUnassignFromCustomer: '&', onDeleteEntityView: '&' } diff --git a/ui/src/app/entity-view/entity-view.routes.js b/ui/src/app/entity-view/entity-view.routes.js index 14f5079d41..481dfc8f90 100644 --- a/ui/src/app/entity-view/entity-view.routes.js +++ b/ui/src/app/entity-view/entity-view.routes.js @@ -35,14 +35,14 @@ export default function EntityViewRoutes($stateProvider, types) { } }, data: { - entityViewsTypes: 'tenant', + entityViewsType: 'tenant', searchEnabled: true, searchByEntitySubtype: true, searchEntityType: types.entityType.entityview, - pageTitle: 'entity-views.entity-views' + pageTitle: 'entity-view.entity-views' }, ncyBreadcrumb: { - label: '{"icon": "devices_other", "label": "entity-view.entity-views"}' + label: '{"icon": "view_stream", "label": "entity-view.entity-views"}' } }) .state('home.customers.entityViews', { @@ -58,14 +58,14 @@ export default function EntityViewRoutes($stateProvider, types) { } }, data: { - entityViewsTypes: 'customer', + entityViewsType: 'customer', searchEnabled: true, searchByEntitySubtype: true, searchEntityType: types.entityType.entityview, pageTitle: 'customer.entity-views' }, ncyBreadcrumb: { - label: '{"icon": "devices_other", "label": "{{ vm.customerEntityViewsTitle }}", "translate": "false"}' + label: '{"icon": "view_stream", "label": "{{ vm.customerEntityViewsTitle }}", "translate": "false"}' } }); diff --git a/ui/src/app/entity-view/entity-views.tpl.html b/ui/src/app/entity-view/entity-views.tpl.html index 5398449273..50a0adb5b1 100644 --- a/ui/src/app/entity-view/entity-views.tpl.html +++ b/ui/src/app/entity-view/entity-views.tpl.html @@ -29,13 +29,12 @@ on-assign-to-customer="vm.assignToCustomer(event, [ vm.grid.detailsConfig.currentItem.id.id ])" on-make-public="vm.makePublic(event, vm.grid.detailsConfig.currentItem)" on-unassign-from-customer="vm.unassignFromCustomer(event, vm.grid.detailsConfig.currentItem, isPublic)" - on-manage-credentials="vm.manageCredentials(event, vm.grid.detailsConfig.currentItem)" on-delete-entity-view="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"> @@ -43,19 +42,19 @@ - - @@ -64,18 +63,11 @@ + entity-type="{{vm.types.entityType.entityView}}"> - - - - - diff --git a/ui/src/app/entity-view/index.js b/ui/src/app/entity-view/index.js index ebdd3ea282..69f669e4cf 100644 --- a/ui/src/app/entity-view/index.js +++ b/ui/src/app/entity-view/index.js @@ -20,7 +20,7 @@ import thingsboardApiEntityView from '../api/entity-view.service'; import thingsboardApiCustomer from '../api/customer.service'; import EntityViewRoutes from './entity-view.routes'; -import EntityViewCardController from './entity-view.controller'; +import {EntityViewController, EntityViewCardController} from './entity-view.controller'; import AssignEntityViewToCustomerController from './assign-to-customer.controller'; import AddEntityViewsToCustomerController from './add-entity-views-to-customer.controller'; import EntityViewDirective from './entity-view.directive'; @@ -33,7 +33,7 @@ export default angular.module('thingsboard.entityView', [ thingsboardApiCustomer ]) .config(EntityViewRoutes) - .controller('EntityViewController', EntityViewCardController) + .controller('EntityViewController', EntityViewController) .controller('EntityViewCardController', EntityViewCardController) .controller('AssignEntityViewToCustomerController', AssignEntityViewToCustomerController) .controller('AddEntityViewsToCustomerController', AddEntityViewsToCustomerController) diff --git a/ui/src/app/layout/index.js b/ui/src/app/layout/index.js index 8f2958d9e3..192400a646 100644 --- a/ui/src/app/layout/index.js +++ b/ui/src/app/layout/index.js @@ -48,6 +48,7 @@ import thingsboardAdmin from '../admin'; import thingsboardProfile from '../profile'; import thingsboardAsset from '../asset'; import thingsboardDevice from '../device'; +import thingsboardEntityView from '../entity-view'; import thingsboardWidgetLibrary from '../widget'; import thingsboardDashboard from '../dashboard'; import thingsboardRuleChain from '../rulechain'; @@ -79,6 +80,7 @@ export default angular.module('thingsboard.home', [ thingsboardProfile, thingsboardAsset, thingsboardDevice, + thingsboardEntityView, thingsboardWidgetLibrary, thingsboardDashboard, thingsboardRuleChain, diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json index 5e04a52a00..09769edc47 100644 --- a/ui/src/app/locale/locale.constant-en_US.json +++ b/ui/src/app/locale/locale.constant-en_US.json @@ -821,7 +821,8 @@ "assignedToCustomer": "Assigned to customer", "unable-entity-view-device-alias-title": "Unable to delete entity view alias", "unable-entity-view-device-alias-text": "Device alias '{{entityViewAlias}}' can't be deleted as it used by the following widget(s):
{{widgetsList}}", - "select-entity-view": "Select entity view" + "select-entity-view": "Select entity view", + "make-public": "Make entity view public" }, "event": { "event-type": "Event type", diff --git a/ui/src/app/services/menu.service.js b/ui/src/app/services/menu.service.js index 1c33d1f18c..869a25d860 100644 --- a/ui/src/app/services/menu.service.js +++ b/ui/src/app/services/menu.service.js @@ -167,6 +167,12 @@ function Menu(userService, $state, $rootScope) { state: 'home.devices', icon: 'devices_other' }, + { + name: 'entity-view.entity-views', + type: 'link', + state: 'home.entityViews', + icon: 'view_stream' + }, { name: 'widget.widget-library', type: 'link', @@ -227,6 +233,16 @@ function Menu(userService, $state, $rootScope) { } ] }, + { + name: 'entity-view.management', + places: [ + { + name: 'entity-view.entity-views', + icon: 'view_stream', + state: 'home.entityViews' + } + ] + }, { name: 'dashboard.management', places: [ @@ -273,6 +289,12 @@ function Menu(userService, $state, $rootScope) { state: 'home.devices', icon: 'devices_other' }, + { + name: 'entity-view.entity-views', + type: 'link', + state: 'home.entityViews', + icon: 'view_stream' + }, { name: 'dashboard.dashboards', type: 'link', @@ -301,16 +323,26 @@ function Menu(userService, $state, $rootScope) { } ] }, - { - name: 'dashboard.view-dashboards', - places: [ - { - name: 'dashboard.dashboards', - icon: 'dashboard', - state: 'home.dashboards' - } - ] - }]; + { + name: 'entity-view.management', + places: [ + { + name: 'entity-view.entity-views', + icon: 'view_stream', + state: 'home.entityViews' + } + ] + }, + { + name: 'dashboard.view-dashboards', + places: [ + { + name: 'dashboard.dashboards', + icon: 'dashboard', + state: 'home.dashboards' + } + ] + }]; } } } From 06a0941dbea59cb975f6f62215e34fd38eb9be07 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Mon, 10 Sep 2018 14:37:46 +0300 Subject: [PATCH 063/118] Entity view misc fixes --- .../controller/EntityViewController.java | 84 +++++++++++++++++++ .../entity-view/entity-view-fieldset.tpl.html | 24 ++++++ .../app/entity-view/entity-view.directive.js | 36 +++++++- ui/src/app/entity-view/entity-view.routes.js | 4 +- ui/src/app/locale/locale.constant-en_US.json | 4 +- 5 files changed, 148 insertions(+), 4 deletions(-) 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 227bed01f3..b5adc327f5 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java @@ -19,16 +19,22 @@ import com.google.common.util.concurrent.ListenableFuture; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; +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.audit.ActionType; import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; import org.thingsboard.server.common.data.exception.ThingsboardException; +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.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.dao.exception.IncorrectParameterException; +import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.service.security.model.SecurityUser; import java.util.ArrayList; @@ -100,6 +106,84 @@ public class EntityViewController extends BaseController { } } + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/customer/{customerId}/entityView/{entityViewId}", method = RequestMethod.POST) + @ResponseBody + public EntityView assignEntityViewToCustomer(@PathVariable("customerId") String strCustomerId, + @PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { + checkParameter("customerId", strCustomerId); + checkParameter(ENTITY_VIEW_ID, strEntityViewId); + try { + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); + Customer customer = checkCustomerId(customerId); + + EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); + checkEntityViewId(entityViewId); + + EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToCustomer(entityViewId, customerId)); + + logEntityAction(entityViewId, savedEntityView, + savedEntityView.getCustomerId(), + ActionType.ASSIGNED_TO_CUSTOMER, null, strEntityViewId, strCustomerId, customer.getName()); + + return savedEntityView; + } catch (Exception e) { + logEntityAction(emptyId(EntityType.ENTITY_VIEW), null, + null, + ActionType.ASSIGNED_TO_CUSTOMER, e, strEntityViewId, strCustomerId); + throw handleException(e); + } + } + + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/customer/entityView/{entityViewId}", method = RequestMethod.DELETE) + @ResponseBody + public EntityView unassignEntityViewFromCustomer(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { + checkParameter(ENTITY_VIEW_ID, strEntityViewId); + try { + EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); + EntityView entityView = checkEntityViewId(entityViewId); + if (entityView.getCustomerId() == null || entityView.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { + throw new IncorrectParameterException("Entity View isn't assigned to any customer!"); + } + Customer customer = checkCustomerId(entityView.getCustomerId()); + + EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromCustomer(entityViewId)); + + logEntityAction(entityViewId, entityView, + entityView.getCustomerId(), + ActionType.UNASSIGNED_FROM_CUSTOMER, null, strEntityViewId, customer.getId().toString(), customer.getName()); + + return savedEntityView; + } catch (Exception e) { + logEntityAction(emptyId(EntityType.ENTITY_VIEW), null, + null, + ActionType.UNASSIGNED_FROM_CUSTOMER, e, strEntityViewId); + throw handleException(e); + } + } + + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/customer/{customerId}/entityViews", params = {"limit"}, method = RequestMethod.GET) + @ResponseBody + public TextPageData getCustomerEntityViews( + @PathVariable("customerId") String strCustomerId, + @RequestParam int limit, + @RequestParam(required = false) String textSearch, + @RequestParam(required = false) String idOffset, + @RequestParam(required = false) String textOffset) throws ThingsboardException { + checkParameter("customerId", strCustomerId); + try { + TenantId tenantId = getCurrentUser().getTenantId(); + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); + checkCustomerId(customerId); + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); + return checkNotNull(entityViewService.findEntityViewsByTenantIdAndCustomerId(tenantId, customerId, pageLink)); + } catch (Exception e) { + throw handleException(e); + } + } + @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/tenant/entityViews", params = {"limit"}, method = RequestMethod.GET) @ResponseBody diff --git a/ui/src/app/entity-view/entity-view-fieldset.tpl.html b/ui/src/app/entity-view/entity-view-fieldset.tpl.html index cb46f3ddf7..c73b0a2493 100644 --- a/ui/src/app/entity-view/entity-view-fieldset.tpl.html +++ b/ui/src/app/entity-view/entity-view-fieldset.tpl.html @@ -52,9 +52,33 @@
entity-view.name-required
+ + +
+ + +
+
+ + +
diff --git a/ui/src/app/entity-view/entity-view.directive.js b/ui/src/app/entity-view/entity-view.directive.js index 5a3d8765a3..b07d4372fb 100644 --- a/ui/src/app/entity-view/entity-view.directive.js +++ b/ui/src/app/entity-view/entity-view.directive.js @@ -20,7 +20,7 @@ import entityViewFieldsetTemplate from './entity-view-fieldset.tpl.html'; /* eslint-enable import/no-unresolved, import/default */ /*@ngInject*/ -export default function EntityViewDirective($compile, $templateCache, toast, $translate, types, clipboardService, entityViewService, customerService) { +export default function EntityViewDirective($compile, $templateCache, $filter, toast, $translate, types, clipboardService, entityViewService, customerService) { var linker = function (scope, element) { var template = $templateCache.get(entityViewFieldsetTemplate); element.html(template); @@ -30,6 +30,8 @@ export default function EntityViewDirective($compile, $templateCache, toast, $tr scope.isPublic = false; scope.assignedCustomer = null; + scope.allowedEntityTypes = [types.entityType.device, types.entityType.asset]; + scope.$watch('entityView', function(newVal) { if (newVal) { if (scope.entityView.customerId && scope.entityView.customerId.id !== types.id.nullUid) { @@ -45,9 +47,41 @@ export default function EntityViewDirective($compile, $templateCache, toast, $tr scope.isPublic = false; scope.assignedCustomer = null; } + scope.startTs = $filter('date')(scope.entityView.endTs, 'yyyy-MM-dd HH:mm:ss'); + scope.endTs = $filter('date')(scope.entityView.startTs, 'yyyy-MM-dd HH:mm:ss'); + } + }); + + + scope.$watch('startTs', function (newDate) { + if (newDate) { + if (newDate.getTime() > scope.maxStartTs) { + scope.startTs = angular.copy(scope.maxStartTs); + } + updateMinMaxDates(); + } + }); + + scope.$watch('endTs', function (newDate) { + if (newDate) { + if (newDate.getTime() < scope.minEndTs) { + scope.endTs = angular.copy(scope.minEndTs); + } + updateMinMaxDates(); } }); + function updateMinMaxDates() { + if (scope.endTs) { + scope.maxStartTs = angular.copy(new Date(scope.endTs.getTime() - 1000)); + scope.entityView.endTs = $filter('date')(scope.endTs, 'yyyy-MM-dd HH:mm:ss'); + } + if (scope.startTs) { + scope.minEndTs = angular.copy(new Date(scope.startTs.getTime() + 1000)); + scope.entityView.startTs = $filter('date')(scope.startTs, 'yyyy-MM-dd HH:mm:ss'); + } + } + scope.onEntityViewIdCopied = function() { toast.showSuccess($translate.instant('entity-view.idCopiedMessage'), 750, angular.element(element).parent().parent(), 'bottom left'); }; diff --git a/ui/src/app/entity-view/entity-view.routes.js b/ui/src/app/entity-view/entity-view.routes.js index 481dfc8f90..c14d430f32 100644 --- a/ui/src/app/entity-view/entity-view.routes.js +++ b/ui/src/app/entity-view/entity-view.routes.js @@ -38,7 +38,7 @@ export default function EntityViewRoutes($stateProvider, types) { entityViewsType: 'tenant', searchEnabled: true, searchByEntitySubtype: true, - searchEntityType: types.entityType.entityview, + searchEntityType: types.entityType.entityView, pageTitle: 'entity-view.entity-views' }, ncyBreadcrumb: { @@ -61,7 +61,7 @@ export default function EntityViewRoutes($stateProvider, types) { entityViewsType: 'customer', searchEnabled: true, searchByEntitySubtype: true, - searchEntityType: types.entityType.entityview, + searchEntityType: types.entityType.entityView, pageTitle: 'customer.entity-views' }, ncyBreadcrumb: { diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json index 09769edc47..e98d4fe1ca 100644 --- a/ui/src/app/locale/locale.constant-en_US.json +++ b/ui/src/app/locale/locale.constant-en_US.json @@ -822,7 +822,9 @@ "unable-entity-view-device-alias-title": "Unable to delete entity view alias", "unable-entity-view-device-alias-text": "Device alias '{{entityViewAlias}}' can't be deleted as it used by the following widget(s):
{{widgetsList}}", "select-entity-view": "Select entity view", - "make-public": "Make entity view public" + "make-public": "Make entity view public", + "start-ts": "Start ts", + "end-ts": "End ts" }, "event": { "event-type": "Event type", From 5139299fd1eb64718528833f45b53f4f91aaebce Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Mon, 10 Sep 2018 14:42:21 +0300 Subject: [PATCH 064/118] Entity view fixes --- .../server/dao/entityview/EntityViewServiceImpl.java | 2 +- ui/src/app/entity-view/entity-view.directive.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) 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 2551183dcf..e90767695d 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 @@ -136,7 +136,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti List list = new ArrayList<>(); list.add(entityView.getTenantId()); list.add(entityView.getName()); - cache.evict(list); +// cache.evict(list); entityViewDao.removeById(entityViewId.getId()); } diff --git a/ui/src/app/entity-view/entity-view.directive.js b/ui/src/app/entity-view/entity-view.directive.js index b07d4372fb..4d4e84b737 100644 --- a/ui/src/app/entity-view/entity-view.directive.js +++ b/ui/src/app/entity-view/entity-view.directive.js @@ -74,11 +74,11 @@ export default function EntityViewDirective($compile, $templateCache, $filter, t function updateMinMaxDates() { if (scope.endTs) { scope.maxStartTs = angular.copy(new Date(scope.endTs.getTime() - 1000)); - scope.entityView.endTs = $filter('date')(scope.endTs, 'yyyy-MM-dd HH:mm:ss'); + scope.entityView.endTs = scope.endTs.getTime(); } if (scope.startTs) { scope.minEndTs = angular.copy(new Date(scope.startTs.getTime() + 1000)); - scope.entityView.startTs = $filter('date')(scope.startTs, 'yyyy-MM-dd HH:mm:ss'); + scope.entityView.startTs = scope.startTs.getTime(); } } From 33fc8f0ba5167130cfc7bb7752142e2bc70ba2c0 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Mon, 10 Sep 2018 15:31:36 +0300 Subject: [PATCH 065/118] Entity view fixes --- ui/src/app/api/entity-view.service.js | 2 +- ui/src/app/api/entity.service.js | 17 +++++++++++++++-- ui/src/app/common/types.constant.js | 6 ++++++ ui/src/app/entity-view/entity-view.directive.js | 4 ++-- .../app/entity/entity-autocomplete.directive.js | 6 ++++++ ui/src/app/locale/locale.constant-en_US.json | 4 ++++ 6 files changed, 34 insertions(+), 5 deletions(-) diff --git a/ui/src/app/api/entity-view.service.js b/ui/src/app/api/entity-view.service.js index f2d190863e..d6d5868959 100644 --- a/ui/src/app/api/entity-view.service.js +++ b/ui/src/app/api/entity-view.service.js @@ -157,7 +157,7 @@ function EntityViewService($http, $q, $window, userService, attributeService, cu var url = '/api/entityView'; entityView.keys = {}; - entityView.keys.timeseries = ['a', 'b']; + entityView.keys.timeseries = ['temp']; $http.post(url, entityView).then(function success(response) { deferred.resolve(response.data); diff --git a/ui/src/app/api/entity.service.js b/ui/src/app/api/entity.service.js index 2e29238dfe..ce4dc42dcd 100644 --- a/ui/src/app/api/entity.service.js +++ b/ui/src/app/api/entity.service.js @@ -20,8 +20,9 @@ export default angular.module('thingsboard.api.entity', [thingsboardTypes]) .name; /*@ngInject*/ -function EntityService($http, $q, $filter, $translate, $log, userService, deviceService, - assetService, tenantService, customerService, ruleChainService, dashboardService, entityRelationService, attributeService, types, utils) { +function EntityService($http, $q, $filter, $translate, $log, userService, deviceService, assetService, tenantService, + customerService, ruleChainService, dashboardService, entityRelationService, attributeService, + entityViewService, types, utils) { var service = { getEntity: getEntity, getEntities: getEntities, @@ -54,6 +55,9 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device case types.entityType.asset: promise = assetService.getAsset(entityId, true, config); break; + case types.entityType.entityView: + promise = entityViewService.getEntityView(entityId, true, config); + break; case types.entityType.tenant: promise = tenantService.getTenant(entityId, config); break; @@ -239,6 +243,13 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device promise = assetService.getTenantAssets(pageLink, false, config, subType); } break; + case types.entityType.entityView: + if (user.authority === 'CUSTOMER_USER') { + promise = entityViewService.getCustomerEntityViews(customerId, pageLink, false, config, subType); + } else { + promise = entityViewService.getTenantEntityViews(pageLink, false, config, subType); + } + break; case types.entityType.tenant: if (user.authority === 'TENANT_ADMIN') { promise = getSingleTenantByPageLinkPromise(pageLink, config); @@ -725,6 +736,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device case 'TENANT_ADMIN': entityTypes.device = types.entityType.device; entityTypes.asset = types.entityType.asset; + entityTypes.entityView = types.entityType.entityView; entityTypes.tenant = types.entityType.tenant; entityTypes.customer = types.entityType.customer; entityTypes.dashboard = types.entityType.dashboard; @@ -735,6 +747,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device case 'CUSTOMER_USER': entityTypes.device = types.entityType.device; entityTypes.asset = types.entityType.asset; + entityTypes.entityView = types.entityType.entityView; entityTypes.customer = types.entityType.customer; entityTypes.dashboard = types.entityType.dashboard; if (useAliasEntityTypes) { diff --git a/ui/src/app/common/types.constant.js b/ui/src/app/common/types.constant.js index 060b557b5d..15da584968 100644 --- a/ui/src/app/common/types.constant.js +++ b/ui/src/app/common/types.constant.js @@ -346,6 +346,12 @@ export default angular.module('thingsboard.types', []) list: 'entity.list-of-assets', nameStartsWith: 'entity.asset-name-starts-with' }, + "ENTITY_VIEW": { + type: 'entity.type-entity-view', + typePlural: 'entity.type-entity-views', + list: 'entity.list-of-entity-views', + nameStartsWith: 'entity.entity-view-name-starts-with' + }, "TENANT": { type: 'entity.type-tenant', typePlural: 'entity.type-tenants', diff --git a/ui/src/app/entity-view/entity-view.directive.js b/ui/src/app/entity-view/entity-view.directive.js index 4d4e84b737..4ec03a12c7 100644 --- a/ui/src/app/entity-view/entity-view.directive.js +++ b/ui/src/app/entity-view/entity-view.directive.js @@ -47,8 +47,8 @@ export default function EntityViewDirective($compile, $templateCache, $filter, t scope.isPublic = false; scope.assignedCustomer = null; } - scope.startTs = $filter('date')(scope.entityView.endTs, 'yyyy-MM-dd HH:mm:ss'); - scope.endTs = $filter('date')(scope.entityView.startTs, 'yyyy-MM-dd HH:mm:ss'); + scope.startTs = new Date(scope.entityView.startTs); + scope.endTs = new Date(scope.entityView.endTs); } }); diff --git a/ui/src/app/entity/entity-autocomplete.directive.js b/ui/src/app/entity/entity-autocomplete.directive.js index e46c614c33..8c1fed76f1 100644 --- a/ui/src/app/entity/entity-autocomplete.directive.js +++ b/ui/src/app/entity/entity-autocomplete.directive.js @@ -131,6 +131,12 @@ export default function EntityAutocomplete($compile, $templateCache, $q, $filter scope.noEntitiesMatchingText = 'device.no-devices-matching'; scope.entityRequiredText = 'device.device-required'; break; + case types.entityType.entityView: + scope.selectEntityText = 'entity-view.select-entity-view'; + scope.entityText = 'entity-view.entity-view'; + scope.noEntitiesMatchingText = 'entity-view.no-entity-views-matching'; + scope.entityRequiredText = 'entity-view.entity-view-required'; + break; case types.entityType.rulechain: scope.selectEntityText = 'rulechain.select-rulechain'; scope.entityText = 'rulechain.rulechain'; diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json index e98d4fe1ca..87a1b1bef4 100644 --- a/ui/src/app/locale/locale.constant-en_US.json +++ b/ui/src/app/locale/locale.constant-en_US.json @@ -708,6 +708,10 @@ "type-assets": "Assets", "list-of-assets": "{ count, plural, 1 {One asset} other {List of # assets} }", "asset-name-starts-with": "Assets whose names start with '{{prefix}}'", + "type-entity-view": "Entity View", + "type-entity-views": "Entity Views", + "list-of-entity-views": "{ count, plural, 1 {One entity view} other {List of # entity views} }", + "entity-view-name-starts-with": "Entity Views whose names start with '{{prefix}}'", "type-rule": "Rule", "type-rules": "Rules", "list-of-rules": "{ count, plural, 1 {One rule} other {List of # rules} }", From 1adb36cd477d673e02359941eba5068efe3ee8c5 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 10 Sep 2018 17:15:11 +0300 Subject: [PATCH 066/118] Was added the filds of start-time and end-time --- .../server/service/telemetry/sub/Subscription.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/sub/Subscription.java b/application/src/main/java/org/thingsboard/server/service/telemetry/sub/Subscription.java index 811c055372..90f606760c 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/sub/Subscription.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/sub/Subscription.java @@ -30,9 +30,11 @@ public class Subscription { private final SubscriptionState sub; private final boolean local; private ServerAddress server; + private long startTime; + private long endTime; public Subscription(SubscriptionState sub, boolean local) { - this(sub, local, null); + this(sub, local, null, 0L, 0L); } public String getWsSessionId() { From 4e39ed53fe3b2ed6a21cebdb0f2da67007a09850 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 10 Sep 2018 19:09:12 +0300 Subject: [PATCH 067/118] Minor changes --- .../DefaultTelemetrySubscriptionService.java | 23 +++++++++++++++++-- .../service/telemetry/sub/Subscription.java | 4 ++++ .../server/dao/model/ModelConstants.java | 2 ++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java index 263b4849fa..ed9e5bc641 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java @@ -27,9 +27,11 @@ import org.springframework.util.StringUtils; import org.thingsboard.rule.engine.api.util.DonAsynchron; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.EntityView; 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.EntityViewId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.BaseTsKvQuery; @@ -44,6 +46,8 @@ import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.kv.TsKvQuery; import org.thingsboard.server.common.msg.cluster.ServerAddress; import org.thingsboard.server.dao.attributes.AttributesService; +import org.thingsboard.server.dao.entityview.EntityViewService; +import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.gen.cluster.ClusterAPIProtos; import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; @@ -97,6 +101,9 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio @Autowired private ClusterRpcService rpcService; + /*@Autowired + private EntityViewService entityViewService;*/ + @Autowired @Lazy private DeviceStateService stateService; @@ -125,17 +132,29 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio @Override public void addLocalWsSubscription(String sessionId, EntityId entityId, SubscriptionState sub) { + String familyName = ModelConstants.DEVICE_FAMILY_NAME; + + //To do + if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) { + familyName = ModelConstants.ENTITY_VIEW_FAMILY_NAME; + //EntityView entityView = entityViewService.findEntityViewById((EntityViewId) entityId) + } + Optional server = routingService.resolveById(entityId); Subscription subscription; if (server.isPresent()) { ServerAddress address = server.get(); - log.trace("[{}] Forwarding subscription [{}] for device [{}] to [{}]", sessionId, sub.getSubscriptionId(), entityId, address); + log.trace("[{}] Forwarding subscription [{}] for " + familyName + " [{}] to [{}]", sessionId, sub.getSubscriptionId(), entityId, address); subscription = new Subscription(sub, true, address); tellNewSubscription(address, sessionId, subscription); } else { - log.trace("[{}] Registering local subscription [{}] for device [{}]", sessionId, sub.getSubscriptionId(), entityId); + log.trace("[{}] Registering local subscription [{}] for " + familyName + " [{}]", sessionId, sub.getSubscriptionId(), entityId); subscription = new Subscription(sub, true); } + + /*if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) { + registerSubscription(sessionId, entityId, subscription); + }*/ registerSubscription(sessionId, entityId, subscription); } diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/sub/Subscription.java b/application/src/main/java/org/thingsboard/server/service/telemetry/sub/Subscription.java index 90f606760c..08440e4bbb 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/sub/Subscription.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/sub/Subscription.java @@ -37,6 +37,10 @@ public class Subscription { this(sub, local, null, 0L, 0L); } + public Subscription(SubscriptionState sub, boolean local, ServerAddress server) { + this(sub, local, server, 0L, 0L); + } + public String getWsSessionId() { return getSub().getWsSessionId(); } 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 a96f258043..7e9662ebe2 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 @@ -131,6 +131,7 @@ public class ModelConstants { * Cassandra device constants. */ public static final String DEVICE_COLUMN_FAMILY_NAME = "device"; + public static final String DEVICE_FAMILY_NAME = "device"; public static final String DEVICE_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; public static final String DEVICE_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY; public static final String DEVICE_NAME_PROPERTY = "name"; @@ -147,6 +148,7 @@ public class ModelConstants { * Cassandra entityView constants. */ public static final String ENTITY_VIEW_TABLE_FAMILY_NAME = "entity_views"; + public static final String ENTITY_VIEW_FAMILY_NAME = "entity-view"; public static final String ENTITY_VIEW_ENTITY_ID_PROPERTY = ENTITY_ID_COLUMN; public static final String ENTITY_VIEW_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; public static final String ENTITY_VIEW_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY; From 0501e9d4b4b4e3a3ec15bf1241ac50550481fff8 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 10 Sep 2018 19:53:29 +0300 Subject: [PATCH 068/118] Was modified addLocalWsSubscription(...) --- .../DefaultTelemetrySubscriptionService.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java index ed9e5bc641..9551f9fe9f 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java @@ -132,14 +132,8 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio @Override public void addLocalWsSubscription(String sessionId, EntityId entityId, SubscriptionState sub) { - String familyName = ModelConstants.DEVICE_FAMILY_NAME; - - //To do - if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) { - familyName = ModelConstants.ENTITY_VIEW_FAMILY_NAME; - //EntityView entityView = entityViewService.findEntityViewById((EntityViewId) entityId) - } - + String familyName = entityId.getEntityType().equals(EntityType.ENTITY_VIEW) + ? ModelConstants.ENTITY_VIEW_FAMILY_NAME : ModelConstants.DEVICE_FAMILY_NAME; Optional server = routingService.resolveById(entityId); Subscription subscription; if (server.isPresent()) { @@ -151,10 +145,6 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio log.trace("[{}] Registering local subscription [{}] for " + familyName + " [{}]", sessionId, sub.getSubscriptionId(), entityId); subscription = new Subscription(sub, true); } - - /*if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) { - registerSubscription(sessionId, entityId, subscription); - }*/ registerSubscription(sessionId, entityId, subscription); } From 08e166d7030e54c15ddf00b379c5d7a1709d625f Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 11 Sep 2018 12:56:43 +0300 Subject: [PATCH 069/118] Added telemetry view --- ui/src/app/api/entity-view.service.js | 3 -- .../entity-view/entity-view-fieldset.tpl.html | 33 +++++++++++++++++++ .../app/entity-view/entity-view.directive.js | 14 +++++++- ui/src/app/locale/locale.constant-en_US.json | 6 +++- 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/ui/src/app/api/entity-view.service.js b/ui/src/app/api/entity-view.service.js index d6d5868959..e34d3a4aee 100644 --- a/ui/src/app/api/entity-view.service.js +++ b/ui/src/app/api/entity-view.service.js @@ -156,9 +156,6 @@ function EntityViewService($http, $q, $window, userService, attributeService, cu var deferred = $q.defer(); var url = '/api/entityView'; - entityView.keys = {}; - entityView.keys.timeseries = ['temp']; - $http.post(url, entityView).then(function success(response) { deferred.resolve(response.data); }, function fail() { diff --git a/ui/src/app/entity-view/entity-view-fieldset.tpl.html b/ui/src/app/entity-view/entity-view-fieldset.tpl.html index c73b0a2493..29287f9bce 100644 --- a/ui/src/app/entity-view/entity-view-fieldset.tpl.html +++ b/ui/src/app/entity-view/entity-view-fieldset.tpl.html @@ -62,6 +62,39 @@ +
+ + + + + + + + + + + + +
Date: Tue, 11 Sep 2018 13:22:34 +0300 Subject: [PATCH 070/118] Fixed dao for customer --- .../server/dao/sql/entityview/JpaEntityViewDao.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 6ef0acba7e..2f3edbe250 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 @@ -100,7 +100,7 @@ public class JpaEntityViewDao extends JpaAbstractSearchTextDao Date: Tue, 11 Sep 2018 15:13:45 +0300 Subject: [PATCH 071/118] Was modified findLatest(...) method & BaseTimeseriesService(...) constructor for set limit and order by values --- .../thingsboard/server/common/data/kv/BaseReadTsKvQuery.java | 4 ++++ .../server/dao/timeseries/BaseTimeseriesService.java | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseReadTsKvQuery.java b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseReadTsKvQuery.java index 3c48adfc18..739586e3e0 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseReadTsKvQuery.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseReadTsKvQuery.java @@ -42,4 +42,8 @@ public class BaseReadTsKvQuery extends BaseTsKvQuery implements ReadTsKvQuery { this(key, startTs, endTs, endTs - startTs, 1, Aggregation.AVG, "DESC"); } + public BaseReadTsKvQuery(String key, long startTs, long endTs, int limit, String orderBy) { + this(key, startTs, endTs, endTs - startTs, limit, Aggregation.AVG, orderBy); + } + } 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 605c9410f6..3829df6904 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 @@ -75,7 +75,10 @@ public class BaseTimeseriesService implements TimeseriesService { EntityView entityView = entityViewService.findEntityViewById((EntityViewId) entityId); Collection matchingKeys = chooseKeysForEntityView(entityView, keys); List queries = new ArrayList<>(); - matchingKeys.forEach(key -> queries.add(new BaseReadTsKvQuery(key, entityView.getStartTs(), entityView.getEndTs()))); + + matchingKeys.forEach(key -> queries.add( + new BaseReadTsKvQuery(key, entityView.getStartTs(), entityView.getEndTs(), 1, "ASC"))); + return timeseriesDao.findAllAsync(entityView.getEntityId(), updateQueriesForEntityView(entityView, queries)); } keys.forEach(key -> futures.add(timeseriesDao.findLatest(entityId, key))); From 770253a32ce950225d8da9836814cc71eb2a3de6 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Tue, 11 Sep 2018 15:59:00 +0300 Subject: [PATCH 072/118] Was fixed the type of startTs & endTs fields of EntityViewEntity class and queries of schemas db tables --- .../main/data/upgrade/2.1.1/schema_update.cql | 20 +++++++++---------- .../main/data/upgrade/2.1.1/schema_update.sql | 4 ++-- .../server/dao/model/ModelConstants.java | 4 ++-- .../dao/model/nosql/EntityViewEntity.java | 16 +++++++-------- .../dao/model/sql/EntityViewEntity.java | 16 +++++++-------- dao/src/main/resources/cassandra/schema.cql | 12 +++++------ dao/src/main/resources/sql/schema.sql | 4 ++-- 7 files changed, 38 insertions(+), 38 deletions(-) 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 1329a0b546..e0cff4108f 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 @@ -29,8 +29,8 @@ CREATE TABLE IF NOT EXISTS thingsboard.entity_views ( customer_id timeuuid, name text, keys text, - ts_begin bigint, - ts_end bigint, + start_ts bigint, + end_ts bigint, search_text text, additional_info text, PRIMARY KEY (id, entity_id, tenant_id, customer_id) @@ -43,8 +43,8 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_na AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL - AND ts_begin IS NOT NULL - AND ts_end IS NOT NULL + AND start_ts IS NOT NULL + AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL PRIMARY KEY (tenant_id, name, id, entity_id, customer_id) @@ -57,8 +57,8 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_en AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL - AND ts_begin IS NOT NULL - AND ts_end IS NOT NULL + AND start_ts IS NOT NULL + AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL PRIMARY KEY (tenant_id, entity_id, id, customer_id, name) @@ -71,8 +71,8 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_cu AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL - AND ts_begin IS NOT NULL - AND ts_end IS NOT NULL + AND start_ts IS NOT NULL + AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL PRIMARY KEY (tenant_id, customer_id, id, entity_id, name) @@ -85,8 +85,8 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_cu AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL - AND ts_begin IS NOT NULL - AND ts_end IS NOT NULL + AND start_ts IS NOT NULL + AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL PRIMARY KEY (tenant_id, customer_id, entity_id, id, name) diff --git a/application/src/main/data/upgrade/2.1.1/schema_update.sql b/application/src/main/data/upgrade/2.1.1/schema_update.sql index 3670aad035..bd2c341e7f 100644 --- a/application/src/main/data/upgrade/2.1.1/schema_update.sql +++ b/application/src/main/data/upgrade/2.1.1/schema_update.sql @@ -24,8 +24,8 @@ CREATE TABLE IF NOT EXISTS entity_views ( customer_id varchar(31), name varchar(255), keys varchar(255), - ts_begin varchar(255), - ts_end varchar(255), + start_ts bigint, + end_ts bigint, search_text varchar(255), additional_info varchar ); 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 7e9662ebe2..a6787d0520 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 @@ -156,8 +156,8 @@ public class ModelConstants { public static final String ENTITY_VIEW_TYPE_PROPERTY = DEVICE_TYPE_PROPERTY; 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_START_TS_PROPERTY = "start_ts"; + public static final String ENTITY_VIEW_END_TS_PROPERTY = "end_ts"; 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"; 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 3f7571363a..91cd2ea563 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 @@ -75,11 +75,11 @@ public class EntityViewEntity implements SearchTextEntity { @Column(name = ModelConstants.ENTITY_VIEW_KEYS_PROPERTY) private String keys; - @Column(name = ModelConstants.ENTITY_VIEW_TS_BEGIN_PROPERTY) - private String tsBegin; + @Column(name = ModelConstants.ENTITY_VIEW_START_TS_PROPERTY) + private long startTs; - @Column(name = ModelConstants.ENTITY_VIEW_TS_END_PROPERTY) - private String tsEnd; + @Column(name = ModelConstants.ENTITY_VIEW_END_TS_PROPERTY) + private long endTs; @Column(name = ModelConstants.SEARCH_TEXT_PROPERTY) private String searchText; @@ -114,8 +114,8 @@ public class EntityViewEntity implements SearchTextEntity { } 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.startTs = entityView.getStartTs() != 0L ? entityView.getStartTs() : 0L; + this.endTs = entityView.getEndTs() != 0L ? entityView.getEndTs() : 0L; this.searchText = entityView.getSearchText(); this.additionalInfo = entityView.getAdditionalInfo(); } @@ -144,8 +144,8 @@ public class EntityViewEntity implements SearchTextEntity { } catch (IOException e) { e.printStackTrace(); } - entityView.setStartTs(Long.parseLong(tsBegin)); - entityView.setEndTs(Long.parseLong(tsEnd)); + entityView.setStartTs(startTs); + entityView.setEndTs(endTs); 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 a89d3dec84..9492f191db 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 @@ -66,11 +66,11 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc @Column(name = ModelConstants.ENTITY_VIEW_KEYS_PROPERTY) private String keys; - @Column(name = ModelConstants.ENTITY_VIEW_TS_BEGIN_PROPERTY) - private String tsBegin; + @Column(name = ModelConstants.ENTITY_VIEW_START_TS_PROPERTY) + private long startTs; - @Column(name = ModelConstants.ENTITY_VIEW_TS_END_PROPERTY) - private String tsEnd; + @Column(name = ModelConstants.ENTITY_VIEW_END_TS_PROPERTY) + private long endTs; @Column(name = ModelConstants.SEARCH_TEXT_PROPERTY) private String searchText; @@ -105,8 +105,8 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc } 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.startTs = entityView.getStartTs() != 0L ? entityView.getStartTs() : 0L; + this.endTs = entityView.getEndTs() != 0L ? entityView.getEndTs() : 0L; this.searchText = entityView.getSearchText(); this.additionalInfo = entityView.getAdditionalInfo(); } @@ -141,8 +141,8 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc } catch (IOException e) { e.printStackTrace(); } - entityView.setStartTs(Long.parseLong(tsBegin)); - entityView.setEndTs(Long.parseLong(tsEnd)); + entityView.setStartTs(startTs); + entityView.setEndTs(endTs); entityView.setAdditionalInfo(additionalInfo); return entityView; } diff --git a/dao/src/main/resources/cassandra/schema.cql b/dao/src/main/resources/cassandra/schema.cql index 89df266d75..3cefacb970 100644 --- a/dao/src/main/resources/cassandra/schema.cql +++ b/dao/src/main/resources/cassandra/schema.cql @@ -647,8 +647,8 @@ CREATE TABLE IF NOT EXISTS thingsboard.entity_views ( customer_id timeuuid, name text, keys text, - ts_begin bigint, - ts_end bigint, + start_ts bigint, + end_ts bigint, search_text text, additional_info text, PRIMARY KEY (id, tenant_id, customer_id) @@ -657,27 +657,27 @@ CREATE TABLE IF NOT EXISTS thingsboard.entity_views ( CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_name AS SELECT * from thingsboard.entity_views - WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND ts_begin IS NOT NULL AND ts_end IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL + WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL PRIMARY KEY (tenant_id, name, id, entity_id, customer_id) WITH CLUSTERING ORDER BY (name ASC, id DESC, entity_id DESC, customer_id DESC); CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_entity AS SELECT * from thingsboard.entity_views - WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND ts_begin IS NOT NULL AND ts_end IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL + WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL PRIMARY KEY (tenant_id, entity_id, id, customer_id, name) WITH CLUSTERING ORDER BY (entity_id ASC, customer_id ASC, id DESC, name DESC); CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer AS SELECT * from thingsboard.entity_views - WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND ts_begin IS NOT NULL AND ts_end IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL + WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL PRIMARY KEY (tenant_id, customer_id, id, entity_id, name) WITH CLUSTERING ORDER BY (customer_id ASC, id DESC, entity_id DESC, name DESC); CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer_and_entity AS SELECT * from thingsboard.entity_views - WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND ts_begin IS NOT NULL AND ts_end IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL + WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL PRIMARY KEY (tenant_id, customer_id, entity_id, id, name) WITH CLUSTERING ORDER BY (customer_id ASC, entity_id DESC, id DESC, name DESC); diff --git a/dao/src/main/resources/sql/schema.sql b/dao/src/main/resources/sql/schema.sql index ed3583cef3..a3197b7e2f 100644 --- a/dao/src/main/resources/sql/schema.sql +++ b/dao/src/main/resources/sql/schema.sql @@ -260,8 +260,8 @@ CREATE TABLE IF NOT EXISTS entity_views ( customer_id varchar(31), name varchar(255), keys varchar(255), - ts_begin varchar(255), - ts_end varchar(255), + start_ts bigint, + end_ts bigint, search_text varchar(255), additional_info varchar ); From cb087d0b53ff3d35b8954c0c73e6ee0bfc8734ad Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Tue, 11 Sep 2018 17:18:51 +0300 Subject: [PATCH 073/118] For testing of entiti-view controller --- .../thingsboard/server/controller/ControllerSqlTestSuite.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 c8a5da8151..a9e94e9184 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.*Test", + "org.thingsboard.server.controller.sql.EntityViewControllerSqlTest", }) public class ControllerSqlTestSuite { From 20e3dc254b9b5a9302a6c8ba4a41b8af7033da3b Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Tue, 11 Sep 2018 17:21:11 +0300 Subject: [PATCH 074/118] To repair the cache --- .../server/dao/entityview/EntityViewServiceImpl.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) 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 e90767695d..5646ac9f53 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 @@ -24,6 +24,7 @@ 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.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Customer; @@ -88,7 +89,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Autowired private CacheManager cacheManager; -// @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}") + @Cacheable(cacheNames = ENTITY_VIEW_CACHE) @Override public EntityView findEntityViewById(EntityViewId entityViewId) { log.trace("Executing findEntityViewById [{}]", entityViewId); @@ -104,7 +105,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti .orElse(null); } -// @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityView.id}") + @CachePut(cacheNames = ENTITY_VIEW_CACHE) @Override public EntityView saveEntityView(EntityView entityView) { log.trace("Executing save entity view [{}]", entityView); @@ -136,7 +137,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti List list = new ArrayList<>(); list.add(entityView.getTenantId()); list.add(entityView.getName()); -// cache.evict(list); + cache.evict(list); entityViewDao.removeById(entityViewId.getId()); } @@ -149,7 +150,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti return new TextPageData<>(entityViews, pageLink); } -// @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #entityId, #pageLink}") + @Cacheable(cacheNames = ENTITY_VIEW_CACHE) @Override public TextPageData findEntityViewByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, TextPageLink pageLink) { @@ -189,7 +190,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti return new TextPageData<>(entityViews, pageLink); } -// @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #customerId, #entityId, #pageLink}") + @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #customerId, #entityId, #pageLink}") @Override public TextPageData findEntityViewsByTenantIdAndCustomerIdAndEntityId(TenantId tenantId, CustomerId customerId, From 09e90b30898575853c020bd4bc55b94f9695a51c Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 12 Sep 2018 09:08:30 +0300 Subject: [PATCH 075/118] Code review fixes --- .../DefaultTelemetrySubscriptionService.java | 12 +--- .../service/telemetry/sub/Subscription.java | 2 +- .../controller/ControllerSqlTestSuite.java | 2 +- .../server/common/data/EntityView.java | 2 +- .../common/data/kv/BaseReadTsKvQuery.java | 2 +- .../dao/entityview/EntityViewServiceImpl.java | 18 +++--- .../dao/timeseries/BaseTimeseriesService.java | 55 +++++++------------ 7 files changed, 34 insertions(+), 59 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java index 35455b9f2e..bdf8e747d4 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java @@ -33,11 +33,8 @@ import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; -//<<<<<<< HEAD import org.thingsboard.server.common.data.id.EntityViewId; -//======= import org.thingsboard.server.common.data.id.TenantId; -//>>>>>>> d909192071880b7af2137333142bc62ece369ec1 import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; @@ -108,9 +105,6 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio @Autowired private ClusterRpcService rpcService; - /*@Autowired - private EntityViewService entityViewService;*/ - @Autowired @Lazy private DeviceStateService stateService; @@ -143,17 +137,15 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio @Override public void addLocalWsSubscription(String sessionId, EntityId entityId, SubscriptionState sub) { - String familyName = entityId.getEntityType().equals(EntityType.ENTITY_VIEW) - ? ModelConstants.ENTITY_VIEW_FAMILY_NAME : ModelConstants.DEVICE_FAMILY_NAME; Optional server = routingService.resolveById(entityId); Subscription subscription; if (server.isPresent()) { ServerAddress address = server.get(); - log.trace("[{}] Forwarding subscription [{}] for " + familyName + " [{}] to [{}]", sessionId, sub.getSubscriptionId(), entityId, address); + log.trace("[{}] Forwarding subscription [{}] for [{}] entity [{}] to [{}]", sessionId, sub.getSubscriptionId(), entityId.getEntityType().name(), entityId, address); subscription = new Subscription(sub, true, address); tellNewSubscription(address, sessionId, subscription); } else { - log.trace("[{}] Registering local subscription [{}] for " + familyName + " [{}]", sessionId, sub.getSubscriptionId(), entityId); + log.trace("[{}] Registering local subscription [{}] for [{}] entity [{}]", sessionId, sub.getSubscriptionId(), entityId.getEntityType().name(), entityId); subscription = new Subscription(sub, true); } registerSubscription(sessionId, entityId, subscription); diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/sub/Subscription.java b/application/src/main/java/org/thingsboard/server/service/telemetry/sub/Subscription.java index 08440e4bbb..47c80e9aa6 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/sub/Subscription.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/sub/Subscription.java @@ -34,7 +34,7 @@ public class Subscription { private long endTime; public Subscription(SubscriptionState sub, boolean local) { - this(sub, local, null, 0L, 0L); + this(sub, local, null); } public Subscription(SubscriptionState sub, boolean local, ServerAddress server) { 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 a9e94e9184..c8a5da8151 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/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 d7ab6e3d54..49dd20959f 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 @@ -1,4 +1,4 @@ - /** +/** * Copyright © 2016-2018 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseReadTsKvQuery.java b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseReadTsKvQuery.java index 739586e3e0..3e4e8ef7a5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseReadTsKvQuery.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseReadTsKvQuery.java @@ -43,7 +43,7 @@ public class BaseReadTsKvQuery extends BaseTsKvQuery implements ReadTsKvQuery { } public BaseReadTsKvQuery(String key, long startTs, long endTs, int limit, String orderBy) { - this(key, startTs, endTs, endTs - startTs, limit, Aggregation.AVG, orderBy); + this(key, startTs, endTs, endTs - startTs, limit, Aggregation.NONE, orderBy); } } 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 5646ac9f53..d2a902b1b2 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 @@ -89,7 +89,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Autowired private CacheManager cacheManager; - @Cacheable(cacheNames = ENTITY_VIEW_CACHE) +// @Cacheable(cacheNames = ENTITY_VIEW_CACHE) @Override public EntityView findEntityViewById(EntityViewId entityViewId) { log.trace("Executing findEntityViewById [{}]", entityViewId); @@ -105,7 +105,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti .orElse(null); } - @CachePut(cacheNames = ENTITY_VIEW_CACHE) +// @CachePut(cacheNames = ENTITY_VIEW_CACHE) @Override public EntityView saveEntityView(EntityView entityView) { log.trace("Executing save entity view [{}]", entityView); @@ -130,14 +130,14 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Override public void deleteEntityView(EntityViewId entityViewId) { log.trace("Executing deleteEntityView [{}]", entityViewId); - Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); +// Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); deleteEntityRelations(entityViewId); EntityView entityView = entityViewDao.findById(entityViewId.getId()); - List list = new ArrayList<>(); - list.add(entityView.getTenantId()); - list.add(entityView.getName()); - cache.evict(list); +// List list = new ArrayList<>(); +// list.add(entityView.getTenantId()); +// list.add(entityView.getName()); +// cache.evict(list); entityViewDao.removeById(entityViewId.getId()); } @@ -150,7 +150,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti return new TextPageData<>(entityViews, pageLink); } - @Cacheable(cacheNames = ENTITY_VIEW_CACHE) +// @Cacheable(cacheNames = ENTITY_VIEW_CACHE) @Override public TextPageData findEntityViewByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, TextPageLink pageLink) { @@ -190,7 +190,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti return new TextPageData<>(entityViews, pageLink); } - @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #customerId, #entityId, #pageLink}") +// @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #customerId, #entityId, #pageLink}") @Override public TextPageData findEntityViewsByTenantIdAndCustomerIdAndEntityId(TenantId tenantId, CustomerId customerId, 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 3829df6904..3a1e8db02f 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 @@ -36,6 +36,7 @@ import org.thingsboard.server.dao.service.Validator; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.stream.Collectors; import static org.apache.commons.lang3.StringUtils.isBlank; @@ -61,7 +62,11 @@ public class BaseTimeseriesService implements TimeseriesService { queries.forEach(BaseTimeseriesService::validate); if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) { EntityView entityView = entityViewService.findEntityViewById((EntityViewId) entityId); - return timeseriesDao.findAllAsync(entityView.getEntityId(), updateQueriesForEntityView(entityView, queries)); + List filteredQueries = + queries.stream() + .filter(query -> entityView.getKeys().getTimeseries().contains(query.getKey())) + .collect(Collectors.toList()); + return timeseriesDao.findAllAsync(entityView.getEntityId(), updateQueriesForEntityView(entityView, filteredQueries)); } return timeseriesDao.findAllAsync(entityId, queries); } @@ -73,11 +78,12 @@ public class BaseTimeseriesService implements TimeseriesService { keys.forEach(key -> Validator.validateString(key, "Incorrect key " + key)); if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) { EntityView entityView = entityViewService.findEntityViewById((EntityViewId) entityId); - Collection matchingKeys = chooseKeysForEntityView(entityView, keys); - List queries = new ArrayList<>(); - - matchingKeys.forEach(key -> queries.add( - new BaseReadTsKvQuery(key, entityView.getStartTs(), entityView.getEndTs(), 1, "ASC"))); + List filteredKeys = new ArrayList<>(keys); + filteredKeys.retainAll(entityView.getKeys().getTimeseries()); + List queries = + filteredKeys.stream() + .map(key -> new BaseReadTsKvQuery(key, entityView.getStartTs(), entityView.getEndTs(), 1, "ASC")) + .collect(Collectors.toList()); return timeseriesDao.findAllAsync(entityView.getEntityId(), updateQueriesForEntityView(entityView, queries)); } @@ -136,34 +142,11 @@ public class BaseTimeseriesService implements TimeseriesService { } private List updateQueriesForEntityView(EntityView entityView, List queries) { - List 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; - } - - private Collection chooseKeysForEntityView(EntityView entityView, Collection keys) { - Collection newKeys = new ArrayList<>(); - entityView.getKeys().getTimeseries() - .forEach(viewKey -> keys - .forEach(key -> { - if (key.equals(viewKey)) { - newKeys.add(key); - } - })); - return newKeys; + return queries.stream().map(query -> { + long startTs = entityView.getStartTs() == 0 ? query.getStartTs() : entityView.getStartTs(); + long endTs = entityView.getEndTs() == 0 ? query.getEndTs() : entityView.getEndTs(); + return updateQuery(startTs, endTs, query); + }).collect(Collectors.toList()); } @Override @@ -205,9 +188,9 @@ public class BaseTimeseriesService implements TimeseriesService { } } - private static ReadTsKvQuery updateQuery(Long startTs, Long endTs, String viewKey, ReadTsKvQuery query) { + private ReadTsKvQuery updateQuery(Long startTs, Long endTs, ReadTsKvQuery query) { return startTs <= query.getStartTs() && endTs >= query.getEndTs() ? query : - new BaseReadTsKvQuery(viewKey, startTs, endTs, query.getInterval(), query.getLimit(), query.getAggregation()); + new BaseReadTsKvQuery(query.getKey(), startTs, endTs, query.getInterval(), query.getLimit(), query.getAggregation()); } private static void checkForNonEntityView(EntityId entityId) throws Exception { From 5dc541eabf3a19522cbb0a522468731d1650cd49 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 12 Sep 2018 09:34:43 +0300 Subject: [PATCH 076/118] Misc fixes --- .../dao/model/nosql/EntityViewEntity.java | 4 +- .../dao/timeseries/BaseTimeseriesService.java | 37 +++++-------------- .../app/entity-view/entity-view.directive.js | 4 +- 3 files changed, 13 insertions(+), 32 deletions(-) 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 91cd2ea563..0545448e55 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 @@ -114,8 +114,8 @@ public class EntityViewEntity implements SearchTextEntity { } catch (IOException e) { e.printStackTrace(); } - this.startTs = entityView.getStartTs() != 0L ? entityView.getStartTs() : 0L; - this.endTs = entityView.getEndTs() != 0L ? entityView.getEndTs() : 0L; + this.startTs = entityView.getStartTs(); + this.endTs = entityView.getEndTs(); this.searchText = entityView.getSearchText(); this.additionalInfo = entityView.getAdditionalInfo(); } 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 3a1e8db02f..629f93a19b 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 @@ -64,7 +64,7 @@ public class BaseTimeseriesService implements TimeseriesService { EntityView entityView = entityViewService.findEntityViewById((EntityViewId) entityId); List filteredQueries = queries.stream() - .filter(query -> entityView.getKeys().getTimeseries().contains(query.getKey())) + .filter(query -> entityView.getKeys().getTimeseries().isEmpty() || entityView.getKeys().getTimeseries().contains(query.getKey())) .collect(Collectors.toList()); return timeseriesDao.findAllAsync(entityView.getEntityId(), updateQueriesForEntityView(entityView, filteredQueries)); } @@ -79,7 +79,9 @@ public class BaseTimeseriesService implements TimeseriesService { if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) { EntityView entityView = entityViewService.findEntityViewById((EntityViewId) entityId); List filteredKeys = new ArrayList<>(keys); - filteredKeys.retainAll(entityView.getKeys().getTimeseries()); + if (!entityView.getKeys().getTimeseries().isEmpty()) { + filteredKeys.retainAll(entityView.getKeys().getTimeseries()); + } List queries = filteredKeys.stream() .map(key -> new BaseReadTsKvQuery(key, entityView.getStartTs(), entityView.getEndTs(), 1, "ASC")) @@ -100,11 +102,6 @@ public class BaseTimeseriesService implements TimeseriesService { @Override public ListenableFuture> 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"); } @@ -115,11 +112,6 @@ public class BaseTimeseriesService implements TimeseriesService { @Override public ListenableFuture> save(EntityId entityId, List tsKvEntries, long ttl) { - try { - checkForNonEntityView(entityId); - } catch (Exception e) { - e.printStackTrace(); - } List> futures = Lists.newArrayListWithExpectedSize(tsKvEntries.size() * INSERTS_PER_ENTRY); for (TsKvEntry tsKvEntry : tsKvEntries) { if (tsKvEntry == null) { @@ -131,10 +123,8 @@ public class BaseTimeseriesService implements TimeseriesService { } private void saveAndRegisterFutures(List> futures, EntityId entityId, TsKvEntry tsKvEntry, long ttl) { - try { - checkForNonEntityView(entityId); - } catch (Exception e) { - e.printStackTrace(); + if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) { + throw new IncorrectParameterException("Telemetry data can't be stored for entity view. Only read only"); } futures.add(timeseriesDao.savePartition(entityId, tsKvEntry.getTs(), tsKvEntry.getKey(), ttl)); futures.add(timeseriesDao.saveLatest(entityId, tsKvEntry)); @@ -145,7 +135,9 @@ public class BaseTimeseriesService implements TimeseriesService { return queries.stream().map(query -> { long startTs = entityView.getStartTs() == 0 ? query.getStartTs() : entityView.getStartTs(); long endTs = entityView.getEndTs() == 0 ? query.getEndTs() : entityView.getEndTs(); - return updateQuery(startTs, endTs, query); + + return startTs <= query.getStartTs() && endTs >= query.getEndTs() ? query : + new BaseReadTsKvQuery(query.getKey(), startTs, endTs, query.getInterval(), query.getLimit(), query.getAggregation()); }).collect(Collectors.toList()); } @@ -187,15 +179,4 @@ public class BaseTimeseriesService implements TimeseriesService { throw new IncorrectParameterException("Incorrect DeleteTsKvQuery. Key can't be empty"); } } - - private ReadTsKvQuery updateQuery(Long startTs, Long endTs, ReadTsKvQuery query) { - return startTs <= query.getStartTs() && endTs >= query.getEndTs() ? query : - new BaseReadTsKvQuery(query.getKey(), 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/ui/src/app/entity-view/entity-view.directive.js b/ui/src/app/entity-view/entity-view.directive.js index e31b0d4acc..c4a35d8cc5 100644 --- a/ui/src/app/entity-view/entity-view.directive.js +++ b/ui/src/app/entity-view/entity-view.directive.js @@ -85,11 +85,11 @@ export default function EntityViewDirective($compile, $templateCache, $filter, t function updateMinMaxDates() { if (scope.endTs) { - scope.maxStartTs = angular.copy(new Date(scope.endTs.getTime() - 1000)); + scope.maxStartTs = angular.copy(new Date(scope.endTs.getTime())); scope.entityView.endTs = scope.endTs.getTime(); } if (scope.startTs) { - scope.minEndTs = angular.copy(new Date(scope.startTs.getTime() + 1000)); + scope.minEndTs = angular.copy(new Date(scope.startTs.getTime())); scope.entityView.startTs = scope.startTs.getTime(); } } From 63395fc8e5c98c70b951623db7ad29939301b2b3 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 12 Sep 2018 12:56:35 +0300 Subject: [PATCH 077/118] Added attribute copying on entity view creation --- .../dao/entityview/EntityViewServiceImpl.java | 49 ++++++++++++++++++- .../attribute/attribute-table.directive.js | 2 +- 2 files changed, 49 insertions(+), 2 deletions(-) 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 d2a902b1b2..f5afad6ec9 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 @@ -16,6 +16,7 @@ package org.thingsboard.server.dao.entityview; import com.google.common.base.Function; +import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; @@ -28,6 +29,7 @@ import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; @@ -40,10 +42,12 @@ import org.thingsboard.server.common.data.id.DeviceId; 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.kv.AttributeKvEntry; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; +import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.customer.CustomerDao; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; @@ -53,6 +57,7 @@ import org.thingsboard.server.dao.tenant.TenantDao; import javax.annotation.Nullable; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -86,6 +91,9 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Autowired private CustomerDao customerDao; + @Autowired + private AttributesService attributesService; + @Autowired private CacheManager cacheManager; @@ -110,7 +118,46 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti public EntityView saveEntityView(EntityView entityView) { log.trace("Executing save entity view [{}]", entityView); entityViewValidator.validate(entityView); - return entityViewDao.save(entityView); + EntityView savedEntityView = entityViewDao.save(entityView); + copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs()); + copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SERVER_SCOPE, savedEntityView.getKeys().getAttributes().getSs()); + copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SHARED_SCOPE, savedEntityView.getKeys().getAttributes().getSh()); + return savedEntityView; + } + + private void copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection keys) { + if (!keys.isEmpty()) { + ListenableFuture> getAttrFuture = attributesService.find(entityView.getEntityId(), scope, keys); + Futures.addCallback(getAttrFuture, new FutureCallback>() { + @Override + public void onSuccess(@Nullable List attributeKvEntries) { + if (attributeKvEntries != null && !attributeKvEntries.isEmpty()) { + List filteredAttributes = + attributeKvEntries.stream() + .filter(attributeKvEntry -> { + if (entityView.getStartTs() == 0 && entityView.getEndTs() == 0) { + return true; + } + if (entityView.getEndTs() == 0 && entityView.getStartTs() < attributeKvEntry.getLastUpdateTs()) { + return true; + } + if (entityView.getStartTs() == 0 && entityView.getEndTs() > attributeKvEntry.getLastUpdateTs()) { + return true; + } + return entityView.getStartTs() < attributeKvEntry.getLastUpdateTs() + && entityView.getEndTs() > attributeKvEntry.getLastUpdateTs(); + }).collect(Collectors.toList()); + attributesService.save(entityView.getId(), scope, filteredAttributes); + } + } + + @Override + public void onFailure(Throwable throwable) { + log.error("Failed to fetch [{}] attributes [{}] for [{}] entity [{}]", + scope, keys, entityView.getEntityId().getEntityType().name(), entityView.getEntityId().getId().toString(), throwable); + } + }); + } } @Override diff --git a/ui/src/app/entity/attribute/attribute-table.directive.js b/ui/src/app/entity/attribute/attribute-table.directive.js index 00618541ce..3a7c164885 100644 --- a/ui/src/app/entity/attribute/attribute-table.directive.js +++ b/ui/src/app/entity/attribute/attribute-table.directive.js @@ -54,7 +54,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS scope.entityType = attrs.entityType; - if (scope.entityType === types.entityType.device) { + if (scope.entityType === types.entityType.device || scope.entityType === types.entityType.entityView) { scope.attributeScopes = types.attributesScope; scope.attributeScopeSelectionReadonly = false; } else { From 0b379d6b6aacd6fcaa4bb08e6347b9b84561825d Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 12 Sep 2018 15:51:18 +0300 Subject: [PATCH 078/118] Fixes for telemetry service subscription --- .../DefaultTelemetrySubscriptionService.java | 7 ++++ .../server/common/data/EntityView.java | 4 +-- .../dao/entityview/EntityViewServiceImpl.java | 23 +++--------- .../dao/model/nosql/EntityViewEntity.java | 8 ++--- .../dao/model/sql/EntityViewEntity.java | 8 ++--- .../dao/timeseries/BaseTimeseriesService.java | 6 ++-- .../entity-view/entity-view-fieldset.tpl.html | 36 ++++++++++--------- .../app/entity-view/entity-view.directive.js | 32 +++++++++-------- ui/src/app/locale/locale.constant-en_US.json | 5 +-- 9 files changed, 65 insertions(+), 64 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java index bdf8e747d4..3ded8827fb 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java @@ -105,6 +105,9 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio @Autowired private ClusterRpcService rpcService; + @Autowired + private EntityViewService entityViewService; + @Autowired @Lazy private DeviceStateService stateService; @@ -137,6 +140,10 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio @Override public void addLocalWsSubscription(String sessionId, EntityId entityId, SubscriptionState sub) { + if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) { + EntityView entityView = entityViewService.findEntityViewById(new EntityViewId(entityId.getId())); + entityId = entityView.getEntityId(); + } Optional server = routingService.resolveById(entityId); Subscription subscription; if (server.isPresent()) { 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 49dd20959f..b86c605464 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 private CustomerId customerId; private String name; private TelemetryEntityView keys; - private long startTs; - private long endTs; + private long startTimeMs; + private long endTimeMs; public EntityView() { super(); 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 f5afad6ec9..d86eabb510 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,30 +15,21 @@ */ package org.thingsboard.server.dao.entityview; -import com.google.common.base.Function; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; 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.CachePut; -import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.DataConstants; -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.device.DeviceSearchQuery; import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; 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.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; @@ -58,13 +49,9 @@ import org.thingsboard.server.dao.tenant.TenantDao; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; -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; @@ -135,17 +122,17 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti List filteredAttributes = attributeKvEntries.stream() .filter(attributeKvEntry -> { - if (entityView.getStartTs() == 0 && entityView.getEndTs() == 0) { + if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() == 0) { return true; } - if (entityView.getEndTs() == 0 && entityView.getStartTs() < attributeKvEntry.getLastUpdateTs()) { + if (entityView.getEndTimeMs() == 0 && entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs()) { return true; } - if (entityView.getStartTs() == 0 && entityView.getEndTs() > attributeKvEntry.getLastUpdateTs()) { + if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs()) { return true; } - return entityView.getStartTs() < attributeKvEntry.getLastUpdateTs() - && entityView.getEndTs() > attributeKvEntry.getLastUpdateTs(); + return entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs() + && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs(); }).collect(Collectors.toList()); attributesService.save(entityView.getId(), scope, filteredAttributes); } 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 0545448e55..79dd497173 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 @@ -114,8 +114,8 @@ public class EntityViewEntity implements SearchTextEntity { } catch (IOException e) { e.printStackTrace(); } - this.startTs = entityView.getStartTs(); - this.endTs = entityView.getEndTs(); + this.startTs = entityView.getStartTimeMs(); + this.endTs = entityView.getEndTimeMs(); this.searchText = entityView.getSearchText(); this.additionalInfo = entityView.getAdditionalInfo(); } @@ -144,8 +144,8 @@ public class EntityViewEntity implements SearchTextEntity { } catch (IOException e) { e.printStackTrace(); } - entityView.setStartTs(startTs); - entityView.setEndTs(endTs); + entityView.setStartTimeMs(startTs); + entityView.setEndTimeMs(endTs); 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 9492f191db..96d187cfb6 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 @@ -105,8 +105,8 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc } catch (IOException e) { e.printStackTrace(); } - this.startTs = entityView.getStartTs() != 0L ? entityView.getStartTs() : 0L; - this.endTs = entityView.getEndTs() != 0L ? entityView.getEndTs() : 0L; + this.startTs = entityView.getStartTimeMs(); + this.endTs = entityView.getEndTimeMs(); this.searchText = entityView.getSearchText(); this.additionalInfo = entityView.getAdditionalInfo(); } @@ -141,8 +141,8 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc } catch (IOException e) { e.printStackTrace(); } - entityView.setStartTs(startTs); - entityView.setEndTs(endTs); + entityView.setStartTimeMs(startTs); + entityView.setEndTimeMs(endTs); 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 629f93a19b..264cdc8f8d 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 @@ -84,7 +84,7 @@ public class BaseTimeseriesService implements TimeseriesService { } List queries = filteredKeys.stream() - .map(key -> new BaseReadTsKvQuery(key, entityView.getStartTs(), entityView.getEndTs(), 1, "ASC")) + .map(key -> new BaseReadTsKvQuery(key, entityView.getStartTimeMs(), entityView.getEndTimeMs(), 1, "ASC")) .collect(Collectors.toList()); return timeseriesDao.findAllAsync(entityView.getEntityId(), updateQueriesForEntityView(entityView, queries)); @@ -133,8 +133,8 @@ public class BaseTimeseriesService implements TimeseriesService { private List updateQueriesForEntityView(EntityView entityView, List queries) { return queries.stream().map(query -> { - long startTs = entityView.getStartTs() == 0 ? query.getStartTs() : entityView.getStartTs(); - long endTs = entityView.getEndTs() == 0 ? query.getEndTs() : entityView.getEndTs(); + long startTs = entityView.getStartTimeMs() == 0 ? query.getStartTs() : entityView.getStartTimeMs(); + long endTs = entityView.getEndTimeMs() == 0 ? query.getEndTs() : entityView.getEndTimeMs(); return startTs <= query.getStartTs() && endTs >= query.getEndTs() ? query : new BaseReadTsKvQuery(query.getKey(), startTs, endTs, query.getInterval(), query.getLimit(), query.getAggregation()); diff --git a/ui/src/app/entity-view/entity-view-fieldset.tpl.html b/ui/src/app/entity-view/entity-view-fieldset.tpl.html index 29287f9bce..b9808e9cea 100644 --- a/ui/src/app/entity-view/entity-view-fieldset.tpl.html +++ b/ui/src/app/entity-view/entity-view-fieldset.tpl.html @@ -95,23 +95,25 @@ md-separator-keys="separatorKeys"> -
- - -
-
- - +
+
+ + +
+
+ + +
diff --git a/ui/src/app/entity-view/entity-view.directive.js b/ui/src/app/entity-view/entity-view.directive.js index c4a35d8cc5..42b3a120fe 100644 --- a/ui/src/app/entity-view/entity-view.directive.js +++ b/ui/src/app/entity-view/entity-view.directive.js @@ -51,8 +51,12 @@ export default function EntityViewDirective($compile, $templateCache, $filter, t scope.isPublic = false; scope.assignedCustomer = null; } - scope.startTs = new Date(scope.entityView.startTs); - scope.endTs = new Date(scope.entityView.endTs); + if (scope.entityView.startTimeMs > 0) { + scope.startTimeMs = new Date(scope.entityView.startTimeMs); + } + if (scope.entityView.endTimeTs > 0) { + scope.endTimeTs = new Date(scope.entityView.endTimeTs); + } if (!scope.entityView.keys) { scope.entityView.keys = {}; scope.entityView.keys.timeseries = []; @@ -65,32 +69,32 @@ export default function EntityViewDirective($compile, $templateCache, $filter, t }); - scope.$watch('startTs', function (newDate) { + scope.$watch('startTimeMs', function (newDate) { if (newDate) { - if (newDate.getTime() > scope.maxStartTs) { - scope.startTs = angular.copy(scope.maxStartTs); + if (newDate.getTime() > scope.maxStartTimeMs) { + scope.startTimeMs = angular.copy(scope.maxStartTimeMs); } updateMinMaxDates(); } }); - scope.$watch('endTs', function (newDate) { + scope.$watch('endTimeTs', function (newDate) { if (newDate) { - if (newDate.getTime() < scope.minEndTs) { - scope.endTs = angular.copy(scope.minEndTs); + if (newDate.getTime() < scope.minEndTimeTs) { + scope.endTimeTs = angular.copy(scope.minEndTimeTs); } updateMinMaxDates(); } }); function updateMinMaxDates() { - if (scope.endTs) { - scope.maxStartTs = angular.copy(new Date(scope.endTs.getTime())); - scope.entityView.endTs = scope.endTs.getTime(); + if (scope.endTimeTs) { + scope.maxStartTimeMs = angular.copy(new Date(scope.endTimeTs.getTime())); + scope.entityView.endTimeTs = scope.endTimeTs.getTime(); } - if (scope.startTs) { - scope.minEndTs = angular.copy(new Date(scope.startTs.getTime())); - scope.entityView.startTs = scope.startTs.getTime(); + if (scope.startTimeMs) { + scope.minEndTimeTs = angular.copy(new Date(scope.startTimeMs.getTime())); + scope.entityView.startTimeMs = scope.startTimeMs.getTime(); } } diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json index 4018c3ac2d..eef7d89056 100644 --- a/ui/src/app/locale/locale.constant-en_US.json +++ b/ui/src/app/locale/locale.constant-en_US.json @@ -827,8 +827,9 @@ "unable-entity-view-device-alias-text": "Device alias '{{entityViewAlias}}' can't be deleted as it used by the following widget(s):
{{widgetsList}}", "select-entity-view": "Select entity view", "make-public": "Make entity view public", - "start-ts": "Start ts", - "end-ts": "End ts", + "start-ts": "Start time", + "end-ts": "End time", + "date-limits": "Date limits", "client-attributes": "Client attributes", "shared-attributes": "Shared attributes", "server-attributes": "Server attributes", From 8ca3e594e8b335a6634e4fc338d9ef3045c3e74c Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 12 Sep 2018 18:24:45 +0300 Subject: [PATCH 079/118] Was added field wich needed for caching --- application/src/main/resources/thingsboard.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index be5149dcb8..362cc29a9b 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -298,6 +298,9 @@ caffeine: assets: timeToLiveInMinutes: 1440 maxSize: 100000 + entityViews: + timeToLiveInMinutes: 1440 + maxSize: 100000 redis: # standalone or cluster From 9a77b2b1997ce09a36396db94a7f2120be362fd9 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 12 Sep 2018 18:43:42 +0300 Subject: [PATCH 080/118] Was fixed the cache --- .../dao/entityview/EntityViewServiceImpl.java | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) 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 f5afad6ec9..dada337f61 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,7 +15,6 @@ */ package org.thingsboard.server.dao.entityview; -import com.google.common.base.Function; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -25,20 +24,15 @@ 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.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.DataConstants; -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.device.DeviceSearchQuery; import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; 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.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; @@ -58,12 +52,9 @@ import org.thingsboard.server.dao.tenant.TenantDao; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; -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; @@ -97,7 +88,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Autowired private CacheManager cacheManager; -// @Cacheable(cacheNames = ENTITY_VIEW_CACHE) + @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId.getId()}") @Override public EntityView findEntityViewById(EntityViewId entityViewId) { log.trace("Executing findEntityViewById [{}]", entityViewId); @@ -105,6 +96,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti return entityViewDao.findById(entityViewId.getId()); } + @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #name}") @Override public EntityView findEntityViewByTenantIdAndName(TenantId tenantId, String name) { log.trace("Executing findEntityViewByTenantIdAndName [{}][{}]", tenantId, name); @@ -113,7 +105,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti .orElse(null); } -// @CachePut(cacheNames = ENTITY_VIEW_CACHE) + @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityView.id, #entityView.tenantId, #entityView.name}") @Override public EntityView saveEntityView(EntityView entityView) { log.trace("Executing save entity view [{}]", entityView); @@ -177,14 +169,13 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Override public void deleteEntityView(EntityViewId entityViewId) { log.trace("Executing deleteEntityView [{}]", entityViewId); -// Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); + Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); deleteEntityRelations(entityViewId); EntityView entityView = entityViewDao.findById(entityViewId.getId()); -// List list = new ArrayList<>(); -// list.add(entityView.getTenantId()); -// list.add(entityView.getName()); -// cache.evict(list); + cache.evict(entityView.getId()); + cache.evict(entityView.getTenantId()); + cache.evict(entityView.getName()); entityViewDao.removeById(entityViewId.getId()); } @@ -197,7 +188,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti return new TextPageData<>(entityViews, pageLink); } -// @Cacheable(cacheNames = ENTITY_VIEW_CACHE) @Override public TextPageData findEntityViewByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, TextPageLink pageLink) { @@ -237,7 +227,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti return new TextPageData<>(entityViews, pageLink); } -// @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #customerId, #entityId, #pageLink}") @Override public TextPageData findEntityViewsByTenantIdAndCustomerIdAndEntityId(TenantId tenantId, CustomerId customerId, From 8f72adfb1d08c03558d8e2a56b2e88fa3fab1e9c Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Thu, 13 Sep 2018 14:08:55 +0300 Subject: [PATCH 081/118] Fixes for time picker --- .../entity-view/entity-view-fieldset.tpl.html | 8 ++++---- .../app/entity-view/entity-view.directive.js | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ui/src/app/entity-view/entity-view-fieldset.tpl.html b/ui/src/app/entity-view/entity-view-fieldset.tpl.html index b9808e9cea..3894eb9d63 100644 --- a/ui/src/app/entity-view/entity-view-fieldset.tpl.html +++ b/ui/src/app/entity-view/entity-view-fieldset.tpl.html @@ -98,19 +98,19 @@
diff --git a/ui/src/app/entity-view/entity-view.directive.js b/ui/src/app/entity-view/entity-view.directive.js index 42b3a120fe..e1ae82fa6a 100644 --- a/ui/src/app/entity-view/entity-view.directive.js +++ b/ui/src/app/entity-view/entity-view.directive.js @@ -54,8 +54,8 @@ export default function EntityViewDirective($compile, $templateCache, $filter, t if (scope.entityView.startTimeMs > 0) { scope.startTimeMs = new Date(scope.entityView.startTimeMs); } - if (scope.entityView.endTimeTs > 0) { - scope.endTimeTs = new Date(scope.entityView.endTimeTs); + if (scope.entityView.endTimeMs > 0) { + scope.endTimeMs = new Date(scope.entityView.endTimeMs); } if (!scope.entityView.keys) { scope.entityView.keys = {}; @@ -78,22 +78,22 @@ export default function EntityViewDirective($compile, $templateCache, $filter, t } }); - scope.$watch('endTimeTs', function (newDate) { + scope.$watch('endTimeMs', function (newDate) { if (newDate) { - if (newDate.getTime() < scope.minEndTimeTs) { - scope.endTimeTs = angular.copy(scope.minEndTimeTs); + if (newDate.getTime() < scope.minEndTimeMs) { + scope.endTimeMs = angular.copy(scope.minEndTimeMs); } updateMinMaxDates(); } }); function updateMinMaxDates() { - if (scope.endTimeTs) { - scope.maxStartTimeMs = angular.copy(new Date(scope.endTimeTs.getTime())); - scope.entityView.endTimeTs = scope.endTimeTs.getTime(); + if (scope.endTimeMs) { + scope.maxStartTimeMs = angular.copy(new Date(scope.endTimeMs.getTime())); + scope.entityView.endTimeMs = scope.endTimeMs.getTime(); } if (scope.startTimeMs) { - scope.minEndTimeTs = angular.copy(new Date(scope.startTimeMs.getTime())); + scope.minEndTimeMs = angular.copy(new Date(scope.startTimeMs.getTime())); scope.entityView.startTimeMs = scope.startTimeMs.getTime(); } } From 3fba214509bcf88f1511ee4c93caa369d56434f8 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Thu, 13 Sep 2018 19:50:49 +0300 Subject: [PATCH 082/118] Was modified values of request mapping annotation --- .../server/controller/EntityViewController.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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 b5adc327f5..48dddcb2b5 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java @@ -51,7 +51,7 @@ public class EntityViewController extends BaseController { public static final String ENTITY_VIEW_ID = "entityViewId"; @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/entityView/{entityViewId}", method = RequestMethod.GET) + @RequestMapping(value = "/entity-view/{entityViewId}", method = RequestMethod.GET) @ResponseBody public EntityView getEntityViewById(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { @@ -66,7 +66,7 @@ public class EntityViewController extends BaseController { } @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/entityView", method = RequestMethod.POST) + @RequestMapping(value = "/entity-view", method = RequestMethod.POST) @ResponseBody public EntityView saveEntityView(@RequestBody EntityView entityView) throws ThingsboardException { try { @@ -86,7 +86,7 @@ public class EntityViewController extends BaseController { } @PreAuthorize("hasAuthority('TENANT_ADMIN')") - @RequestMapping(value = "/entityView/{entityViewId}", method = RequestMethod.DELETE) + @RequestMapping(value = "/entity-view/{entityViewId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) public void deleteEntityView(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { checkParameter(ENTITY_VIEW_ID, strEntityViewId); @@ -107,7 +107,7 @@ public class EntityViewController extends BaseController { } @PreAuthorize("hasAuthority('TENANT_ADMIN')") - @RequestMapping(value = "/customer/{customerId}/entityView/{entityViewId}", method = RequestMethod.POST) + @RequestMapping(value = "/customer/{customerId}/entity-view/{entityViewId}", method = RequestMethod.POST) @ResponseBody public EntityView assignEntityViewToCustomer(@PathVariable("customerId") String strCustomerId, @PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { @@ -136,7 +136,7 @@ public class EntityViewController extends BaseController { } @PreAuthorize("hasAuthority('TENANT_ADMIN')") - @RequestMapping(value = "/customer/entityView/{entityViewId}", method = RequestMethod.DELETE) + @RequestMapping(value = "/customer/entity-view/{entityViewId}", method = RequestMethod.DELETE) @ResponseBody public EntityView unassignEntityViewFromCustomer(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { checkParameter(ENTITY_VIEW_ID, strEntityViewId); @@ -164,7 +164,7 @@ public class EntityViewController extends BaseController { } @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/customer/{customerId}/entityViews", params = {"limit"}, method = RequestMethod.GET) + @RequestMapping(value = "/customer/{customerId}/entity-views", params = {"limit"}, method = RequestMethod.GET) @ResponseBody public TextPageData getCustomerEntityViews( @PathVariable("customerId") String strCustomerId, @@ -185,7 +185,7 @@ public class EntityViewController extends BaseController { } @PreAuthorize("hasAuthority('TENANT_ADMIN')") - @RequestMapping(value = "/tenant/entityViews", params = {"limit"}, method = RequestMethod.GET) + @RequestMapping(value = "/tenant/entity-views", params = {"limit"}, method = RequestMethod.GET) @ResponseBody public TextPageData getTenantEntityViews( @RequestParam int limit, @@ -202,7 +202,7 @@ public class EntityViewController extends BaseController { } @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/entityViews", method = RequestMethod.POST) + @RequestMapping(value = "/entity-views", method = RequestMethod.POST) @ResponseBody public List findByQuery(@RequestBody EntityViewSearchQuery query) throws ThingsboardException { checkNotNull(query); From 7c14df56e3aa71a5eb9289e080dfff0704cbbb38 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Thu, 13 Sep 2018 19:51:40 +0300 Subject: [PATCH 083/118] Was added new tests --- .../BaseEntityViewControllerTest.java | 275 ++++++++++++++++-- 1 file changed, 244 insertions(+), 31 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index c7ac98d413..920ce139cc 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -15,25 +15,34 @@ */ package org.thingsboard.server.controller; +import com.datastax.driver.core.utils.UUIDs; +import com.fasterxml.jackson.core.type.TypeReference; +import org.apache.commons.lang3.RandomStringUtils; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.EntityView; -import org.thingsboard.server.common.data.Tenant; -import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.*; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.objects.AttributesEntityView; import org.thingsboard.server.common.data.objects.TelemetryEntityView; +import org.thingsboard.server.common.data.page.TextPageData; +import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.dao.model.ModelConstants; -import java.util.Arrays; +import java.util.*; +import java.util.stream.Stream; +import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; public abstract class BaseEntityViewControllerTest extends AbstractControllerTest { + private IdComparator idComparator; private Tenant savedTenant; private User tenantAdmin; private Device testDevice; @@ -43,6 +52,8 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes public void beforeTest() throws Exception { loginSysAdmin(); + idComparator = new IdComparator<>(); + Tenant tenant = new Tenant(); tenant.setTitle("My tenant"); savedTenant = doPost("/api/tenant", tenant, Tenant.class); @@ -62,13 +73,14 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes device.setName("Test device"); device.setType("default"); testDevice = doPost("/api/device", device, Device.class); - obj = new TelemetryEntityView( Arrays.asList("109L", "209L"), new AttributesEntityView( - Arrays.asList("caKey1", "caKey2", "caKey3"), - Arrays.asList("saKey1", "saKey2", "saKey3", "saKey4"), - Arrays.asList("shKey1", "shKey2", "shKey3", "shKey4", "shKey5"))); + Arrays.asList("caKey1", "caKey2"), + Arrays.asList("saKey1", "saKey2", "saKey3"), + Arrays.asList("shKey1", "shKey2", "shKey3", "shKey4") + ) + ); } @After @@ -81,24 +93,15 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes @Test public void testFindEntityViewById() throws Exception { - EntityView view = new EntityView(); - view.setName("Test entity view"); - view.setEntityId(testDevice.getId()); - view.setKeys(new TelemetryEntityView(obj)); - EntityView savedView = doPost("/api/entity-view", view, EntityView.class); + EntityView savedView = doPost("/api/entity-view", getNewEntityView("Test entity view"), EntityView.class); EntityView foundView = doGet("/api/entity-view/" + savedView.getId().getId().toString(), EntityView.class); Assert.assertNotNull(foundView); Assert.assertEquals(savedView, foundView); } @Test - public void testSaveEntityViewWithIdOfDevice() throws Exception { - EntityView view = new EntityView(); - view.setEntityId(testDevice.getId()); - view.setName("Test entity view"); - view.setTenantId(savedTenant.getId()); - view.setKeys(new TelemetryEntityView(obj)); - EntityView savedView = doPost("/api/entity-view", view, EntityView.class); + public void testSaveEntityView() throws Exception { + EntityView savedView = doPost("/api/entity-view", getNewEntityView("Test entity view"), EntityView.class); Assert.assertNotNull(savedView); Assert.assertNotNull(savedView.getId()); @@ -110,25 +113,235 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes savedView.setName("New test entity view"); doPost("/api/entity-view", savedView, EntityView.class); - - EntityView foundEntityView = doGet("/api/entity-view/" - + savedView.getId().getId().toString(), EntityView.class); + EntityView foundEntityView = doGet("/api/entity-view/" + savedView.getId().getId().toString(), EntityView.class); Assert.assertEquals(foundEntityView.getName(), savedView.getName()); } @Test public void testDeleteEntityView() throws Exception { - EntityView view = new EntityView(); - view.setName("Test entity view"); - view.setEntityId(testDevice.getId()); - view.setKeys(new TelemetryEntityView((TelemetryEntityView) obj)); - EntityView savedView = doPost("/api/entity-view", view, EntityView.class); - + EntityView savedView = doPost("/api/entity-view", getNewEntityView("Test entity view"), EntityView.class); doDelete("/api/entity-view/" + savedView.getId().getId().toString()) .andExpect(status().isOk()); - doGet("/api/entity-view/" + savedView.getId().getId().toString()) .andExpect(status().isNotFound()); } + + @Test + public void testSaveEntityViewWithEmptyName() throws Exception { + doPost("/api/entity-view", getNewEntityView("Entity view")) + .andExpect(status().isBadRequest()) + .andExpect(statusReason(containsString("Entity-view name should be specified"))); + } + + @Test + public void testAssignAndUnAssignedEntityViewToCustomer() throws Exception { + EntityView savedView = doPost("/api/entity-view", getNewEntityView("Test entity view"), EntityView.class); + Customer savedCustomer = doPost("/api/customer", getNewCustomer("My customer"), Customer.class); + EntityView assignedView = doPost("/api/customer/" + savedCustomer.getId().getId().toString() + + "/entity-view/" + savedView.getId().getId().toString(), EntityView.class); + Assert.assertEquals(savedCustomer.getId(), assignedView.getCustomerId()); + + EntityView foundView = doGet("/api/entity-view" + savedView.getId().getId().toString(), EntityView.class); + Assert.assertEquals(savedCustomer.getId(), foundView.getCustomerId()); + + EntityView unAssignedView = doDelete("/api/customer/entity-view/" + savedView.getId().getId().toString(), EntityView.class); + Assert.assertEquals(ModelConstants.NULL_UUID, unAssignedView.getCustomerId().getId()); + + foundView = doGet("/api/entity-view/" + savedView.getId().getId().toString(), EntityView.class); + Assert.assertEquals(ModelConstants.NULL_UUID, foundView.getCustomerId().getId()); + } + + @Test + public void testAssignEntityViewToNonExistentCustomer() throws Exception { + EntityView savedView = doPost("/api/entity-view", getNewEntityView("Test entity view"), EntityView.class); + doPost("/api/customer/" + UUIDs.timeBased().toString() + "/device/" + savedView.getId().getId().toString()) + .andExpect(status().isNotFound()); + } + + @Test + public void testAssignEntityViewToCustomerFromDifferentTenant() throws Exception { + loginSysAdmin(); + + Tenant savedAnotherTenant = doPost("/api/tenant", getNewTenant("Different tenant"), Tenant.class); + Assert.assertNotNull(savedAnotherTenant); + + User adminAnotherTenant = new User(); + adminAnotherTenant.setAuthority(Authority.TENANT_ADMIN); + adminAnotherTenant.setTenantId(savedAnotherTenant.getId()); + adminAnotherTenant.setEmail("tenant3@thingsboard.org"); + adminAnotherTenant.setFirstName("Joe"); + adminAnotherTenant.setLastName("Downs"); + createUserAndLogin(adminAnotherTenant, "testPassword1"); + + Customer savedCustomer = doPost("/api/customer", getNewCustomer("Different customer"), Customer.class); + login(tenantAdmin.getEmail(), "testPassword1"); + + EntityView savedView = doPost("/api/entity-view", getNewEntityView("Test entity view"), EntityView.class); + doPost("/api/customer/" + savedCustomer.getId().getId().toString() + "/entity-view/" + savedView.getId().getId().toString()) + .andExpect(status().isForbidden()); + + loginSysAdmin(); + + doDelete("/api/tenant/" + savedAnotherTenant.getId().getId().toString()) + .andExpect(status().isOk()); + } + + @Test + public void testGetCustomerEntityViews() throws Exception { + CustomerId customerId = doPost("/api/customer", getNewCustomer("Test customer"), Customer.class).getId(); + String urlTemplate = "/api/customer/" + customerId.getId().toString() + "/entity-views?"; + + List views = new ArrayList<>(); + for (int i = 0; i < 128; i++) { + views.add(doPost("/api/customer/" + customerId.getId().toString() + "/entity-view/" + + getNewEntityView("Test entity view " + i).getId().getId().toString(), EntityView.class)); + } + + List loadedViews = loadListOf(new TextPageLink(23), urlTemplate); + + Collections.sort(views, idComparator); + Collections.sort(loadedViews, idComparator); + + Assert.assertEquals(views, loadedViews); + } + + @Test + public void testGetCustomerEntityViewsByName() throws Exception { + CustomerId customerId = doPost("/api/customer", getNewCustomer("Test customer"), Customer.class).getId(); + String urlTemplate = "/api/customer/" + customerId.getId().toString() + "/entity-views?"; + + String name1 = "Entity view name1"; + List namesOfView1 = fillListOf(125, name1, "/api/customer/" + customerId.getId().toString() + + "/entity-view/"); + List loadedNamesOfView1 = loadListOf(new TextPageLink(15, name1), urlTemplate); + Collections.sort(namesOfView1, idComparator); + Collections.sort(loadedNamesOfView1, idComparator); + Assert.assertEquals(namesOfView1, loadedNamesOfView1); + + String name2 = "Entity view name2"; + List NamesOfView2 = fillListOf(143, name2, "/api/customer/" + customerId.getId().toString() + + "/entity-view/"); + List loadedNamesOfView2 = loadListOf(new TextPageLink(4, name2), urlTemplate); + Collections.sort(NamesOfView2, idComparator); + Collections.sort(loadedNamesOfView2, idComparator); + Assert.assertEquals(NamesOfView2, loadedNamesOfView2); + + for (EntityView view : loadedNamesOfView1) { + doDelete("/api/customer/entity-view/" + view.getId().getId().toString()).andExpect(status().isOk()); + } + TextPageData pageData = doGetTypedWithPageLink(urlTemplate, + new TypeReference>(){}, new TextPageLink(4, name1)); + Assert.assertFalse(pageData.hasNext()); + Assert.assertEquals(0, pageData.getData().size()); + + for (EntityView view : loadedNamesOfView2) { + doDelete("/api/customer/entity-view/" + view.getId().getId().toString()).andExpect(status().isOk()); + } + pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference>(){}, + new TextPageLink(4, name2)); + Assert.assertFalse(pageData.hasNext()); + Assert.assertEquals(0, pageData.getData().size()); + } + + @Test + public void testGetTenantEntityViews() throws Exception { + + List views = new ArrayList<>(); + for (int i = 0; i < 178; i++) { + views.add(doPost("/api/entity-view/", getNewEntityView("Test entity view" + i), EntityView.class)); + } + List loadedViews = loadListOf(new TextPageLink(23), "/api/tenant/entity-views?"); + + Collections.sort(views, idComparator); + Collections.sort(loadedViews, idComparator); + + Assert.assertEquals(views, loadedViews); + } + + @Test + public void testGetTenantEntityViewsByName() throws Exception { + String name1 = "Entity view name1"; + List namesOfView1 = fillListOf(143, name1); + List loadedNamesOfView1 = loadListOf(new TextPageLink(15, name1), "/api/tenant/entity-views?"); + Collections.sort(namesOfView1, idComparator); + Collections.sort(loadedNamesOfView1, idComparator); + Assert.assertEquals(namesOfView1, loadedNamesOfView1); + + String name2 = "Entity view name2"; + List NamesOfView2 = fillListOf(75, name2); + List loadedNamesOfView2 = loadListOf(new TextPageLink(4, name2), "/api/tenant/entity-views?"); + Collections.sort(NamesOfView2, idComparator); + Collections.sort(loadedNamesOfView2, idComparator); + Assert.assertEquals(NamesOfView2, loadedNamesOfView2); + + for (EntityView view : loadedNamesOfView1) { + doDelete("/api/entity-view/" + view.getId().getId().toString()).andExpect(status().isOk()); + } + TextPageData pageData = doGetTypedWithPageLink("/api/tenant/entity-views?", + new TypeReference>(){}, new TextPageLink(4, name1)); + Assert.assertFalse(pageData.hasNext()); + Assert.assertEquals(0, pageData.getData().size()); + + for (EntityView view : loadedNamesOfView2) { + doDelete("/api/entity-view/" + view.getId().getId().toString()).andExpect(status().isOk()); + } + pageData = doGetTypedWithPageLink("/api/tenant/entity-views?", new TypeReference>(){}, + new TextPageLink(4, name2)); + Assert.assertFalse(pageData.hasNext()); + Assert.assertEquals(0, pageData.getData().size()); + } + + private EntityView getNewEntityView(String name) throws Exception { + EntityView view = new EntityView(); + view.setName(name); + view.setEntityId(testDevice.getId()); + view.setTenantId(savedTenant.getId()); + view.setKeys(new TelemetryEntityView(obj)); + return doPost("/api/entity-view", view, EntityView.class); + } + + private Customer getNewCustomer(String title) { + Customer customer = new Customer(); + customer.setTitle(title); + return customer; + } + + private Tenant getNewTenant(String title) { + Tenant tenant = new Tenant(); + tenant.setTitle(title); + return tenant; + } + + private List fillListOf(int limit, String partOfName, String urlTemplate) throws Exception { + List views = new ArrayList<>(); + for (EntityView view : fillListOf(limit, partOfName)) { + views.add(doPost(urlTemplate + view.getId().getId().toString(), EntityView.class)); + } + return views; + } + + private List fillListOf(int limit, String partOfName) throws Exception { + List viewNames = new ArrayList<>(); + for (int i = 0; i < limit; i++) { + String fullName = partOfName + ' ' + RandomStringUtils.randomAlphanumeric(15); + fullName = i % 2 == 0 ? fullName.toLowerCase() : fullName.toUpperCase(); + viewNames.add(doPost("/api/entity-view", getNewEntityView(fullName), EntityView.class)); + } + return viewNames; + } + + private List loadListOf(TextPageLink pageLink, String urlTemplate) throws Exception { + List loadedItems = new ArrayList<>(); + TextPageData pageData; + do { + pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference>(){}, pageLink); + loadedItems.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageData.getNextPageLink(); + } + } while (pageData.hasNext()); + + return loadedItems; + } } From 020b7a4ec68a8e4006d78697cbb81480989209c9 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Fri, 14 Sep 2018 14:04:12 +0300 Subject: [PATCH 084/118] Added copy attributes to entity view rule node --- .../server/actors/ActorSystemContext.java | 5 + .../actors/ruleChain/DefaultTbContext.java | 6 + .../entityview/CassandraEntityViewDao.java | 7 + .../server/dao/entityview/EntityViewDao.java | 4 + .../dao/entityview/EntityViewService.java | 3 + .../dao/entityview/EntityViewServiceImpl.java | 12 ++ .../sql/entityview/EntityViewRepository.java | 3 + .../dao/sql/entityview/JpaEntityViewDao.java | 8 ++ .../rule/engine/api/TbContext.java | 3 + .../TbCopyAttributesToEntityViewNode.java | 122 ++++++++++++++++++ 10 files changed, 173 insertions(+) create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java diff --git a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java index d33734e14c..e3682dec8c 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java @@ -48,6 +48,7 @@ import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.audit.AuditLogService; 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.event.EventService; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; @@ -159,6 +160,10 @@ public class ActorSystemContext { @Getter private AuditLogService auditLogService; + @Autowired + @Getter + private EntityViewService entityViewService; + @Autowired @Getter private TelemetrySubscriptionService tsSubService; diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java index 7279347b1c..acfc269fd5 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -41,6 +41,7 @@ import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.attributes.AttributesService; 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.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.tenant.TenantService; @@ -212,6 +213,11 @@ class DefaultTbContext implements TbContext { return mainCtx.getRelationService(); } + @Override + public EntityViewService getEntityViewService() { + return mainCtx.getEntityViewService(); + } + @Override public MailService getMailService() { if (mainCtx.isAllowSystemMailService()) { 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 5716460d20..5de34e4b71 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 @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.entityview; import com.datastax.driver.core.Statement; import com.datastax.driver.core.querybuilder.Select; +import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.EntitySubtype; @@ -105,4 +106,10 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao findEntityViewsByTenantIdAndCustomerIdAndEntityId(UUID tenantId, UUID customerId, UUID entityId, TextPageLink pageLink) { return null; } + + @Override + public ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(UUID tenantId, UUID entityId) { + // TODO: implement this + 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 56a688ae47..be643ef363 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 @@ -15,6 +15,8 @@ */ package org.thingsboard.server.dao.entityview; +import com.google.common.util.concurrent.ListenableFuture; +import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.dao.Dao; @@ -91,4 +93,6 @@ public interface EntityViewDao extends Dao { UUID customerId, UUID entityId, TextPageLink pageLink); + + ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(UUID tenantId, UUID entityId); } 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 a60376e501..b9c238a79a 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 @@ -20,6 +20,7 @@ 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.device.DeviceSearchQuery; import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; import org.thingsboard.server.common.data.id.*; @@ -65,4 +66,6 @@ public interface EntityViewService { ListenableFuture findEntityViewByIdAsync(EntityViewId entityViewId); ListenableFuture> findEntityViewsByQuery(EntityViewSearchQuery query); + + ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId); } 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 d86eabb510..598897aac5 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 @@ -25,11 +25,13 @@ import org.springframework.cache.CacheManager; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.DataConstants; +import org.thingsboard.server.common.data.Device; 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.entityview.EntityViewSearchQuery; 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.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; @@ -52,8 +54,10 @@ import java.util.Collection; import java.util.List; import java.util.stream.Collectors; +import static org.thingsboard.server.dao.DaoUtil.toUUIDs; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; import static org.thingsboard.server.dao.service.Validator.validateId; +import static org.thingsboard.server.dao.service.Validator.validateIds; import static org.thingsboard.server.dao.service.Validator.validatePageLink; import static org.thingsboard.server.dao.service.Validator.validateString; @@ -277,6 +281,14 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti return entityViews; } + @Override + public ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId) { + log.trace("Executing findEntityViewsByTenantIdAndEntityIdAsync, tenantId [{}], entityId [{}]", tenantId, entityId); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateId(entityId.getId(), "Incorrect entityId" + entityId); + return entityViewDao.findEntityViewsByTenantIdAndEntityIdAsync(tenantId.getId(), entityId.getId()); + } + private DataValidator entityViewValidator = new DataValidator() { 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 27bd8395ac..f1ee3fd272 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 @@ -19,6 +19,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; +import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.dao.model.sql.EntityViewEntity; import org.thingsboard.server.dao.util.SqlDao; @@ -78,4 +79,6 @@ public interface EntityViewRepository extends CrudRepository entityViewsIds); List findAllByTenantIdAndIdIn(String tenantId, List entityViewsIds); + + List findAllByTenantIdAndEntityId(String tenantId, String entityId); } 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 2f3edbe250..4ff21ab892 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 @@ -23,6 +23,7 @@ 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.UUIDConverter; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageLink; @@ -40,6 +41,7 @@ import java.util.Optional; import java.util.UUID; import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUID; +import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUIDs; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID_STR; /** @@ -121,4 +123,10 @@ public class JpaEntityViewDao extends JpaAbstractSearchTextDao> findEntityViewsByTenantIdAndEntityIdAsync(UUID tenantId, UUID entityId) { + return service.submit(() -> DaoUtil.convertDataList( + entityViewRepository.findAllByTenantIdAndEntityId(UUIDConverter.fromTimeUUID(tenantId), UUIDConverter.fromTimeUUID(entityId)))); + } } diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java index e7ef0dd40f..f9d3c64211 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java @@ -26,6 +26,7 @@ import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.attributes.AttributesService; 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.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.tenant.TenantService; @@ -83,6 +84,8 @@ public interface TbContext { RelationService getRelationService(); + EntityViewService getEntityViewService(); + ListeningExecutor getJsExecutor(); ListeningExecutor getMailExecutor(); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java new file mode 100644 index 0000000000..73999afb97 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java @@ -0,0 +1,122 @@ +package org.thingsboard.rule.engine.action; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.base.Function; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.gson.JsonParser; +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; +import org.thingsboard.rule.engine.api.RuleNode; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.DataConstants; +import org.thingsboard.server.common.data.EntityView; +import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.plugin.ComponentType; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.session.SessionMsgType; +import org.thingsboard.server.common.transport.adaptor.JsonConverter; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; + +import static org.thingsboard.rule.engine.api.util.DonAsynchron.withCallback; + +@Slf4j +@RuleNode( + type = ComponentType.ACTION, + name = "copy attributes", + configClazz = EmptyNodeConfiguration.class, + nodeDescription = "Copy attributes from asset/device to entity view", + nodeDetails = "Copy attributes from asset/device to related entity view according to entity view configuration. \n " + + "Copy will be done only for attributes that are between start and end dates and according to attribute keys configuration", + uiResources = {"static/rulenode/rulenode-core-config.js"}, + configDirective = "tbNodeEmptyConfig", + icon = "content_copy" +) +public class TbCopyAttributesToEntityViewNode implements TbNode { + + EmptyNodeConfiguration config; + + @Override + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + this.config = TbNodeUtils.convert(configuration, EmptyNodeConfiguration.class); + } + + @Override + public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException { + if (msg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name()) || + msg.getType().equals(DataConstants.ATTRIBUTES_DELETED) || + msg.getType().equals(DataConstants.ATTRIBUTES_UPDATED)) { + long now = System.currentTimeMillis(); + String scope; + if (msg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name())) { + scope = DataConstants.CLIENT_SCOPE; + } else { + scope = msg.getMetaData().getValue("scope"); + } + ListenableFuture> entityViewsFuture = + ctx.getEntityViewService().findEntityViewsByTenantIdAndEntityIdAsync(ctx.getTenantId(), msg.getOriginator()); + withCallback(entityViewsFuture, + entityViews -> { + List>> saveFutures = new ArrayList<>(); + for (EntityView entityView : entityViews) { + if ((entityView.getEndTimeMs() != 0 && entityView.getEndTimeMs() > now && entityView.getStartTimeMs() < now) || + (entityView.getEndTimeMs() == 0 && entityView.getStartTimeMs() < now)) { + Set attributes = JsonConverter.convertToAttributes(new JsonParser().parse(msg.getData())).getAttributes(); + List filteredAttributes = + attributes.stream() + .filter(attr -> { + switch (scope) { + case DataConstants.CLIENT_SCOPE: + if (entityView.getKeys().getAttributes().getCs().isEmpty()) { + return true; + } + return entityView.getKeys().getAttributes().getCs().contains(attr.getKey()); + case DataConstants.SERVER_SCOPE: + if (entityView.getKeys().getAttributes().getSs().isEmpty()) { + return true; + } + return entityView.getKeys().getAttributes().getSs().contains(attr.getKey()); + case DataConstants.SHARED_SCOPE: + if (entityView.getKeys().getAttributes().getSh().isEmpty()) { + return true; + } + return entityView.getKeys().getAttributes().getSh().contains(attr.getKey()); + } + return false; + }) + .collect(Collectors.toList()); + saveFutures.add(ctx.getAttributesService().save(entityView.getId(), scope, new ArrayList<>(filteredAttributes))); + } + } + Futures.transform(Futures.allAsList(saveFutures), new Function>, Object>() { + @Nullable + @Override + public Object apply(@Nullable List> lists) { + ctx.tellNext(msg, TbRelationTypes.SUCCESS); + return null; + } + }); + }, + t -> ctx.tellFailure(msg, t)); + } else { + ctx.tellNext(msg, TbRelationTypes.FAILURE); + } + } + + @Override + public void destroy() { + + } +} From 3b0d7204bc93c17ef837f3be748710ad85dbc528 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Fri, 14 Sep 2018 14:05:29 +0300 Subject: [PATCH 085/118] Added copy attributes to entity view rule node --- .../action/TbCopyAttributesToEntityViewNode.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java index 73999afb97..d609620edf 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java @@ -1,3 +1,18 @@ +/** + * 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.rule.engine.action; import com.fasterxml.jackson.databind.ObjectMapper; From 5180961ecb4611c23baa2ed079433e62fe3da5d3 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Fri, 14 Sep 2018 15:12:55 +0300 Subject: [PATCH 086/118] Was modified of request mapping values --- .../controller/EntityViewController.java | 16 ++-- .../BaseEntityViewControllerTest.java | 96 ++++++++++--------- 2 files changed, 58 insertions(+), 54 deletions(-) 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 48dddcb2b5..b5adc327f5 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java @@ -51,7 +51,7 @@ public class EntityViewController extends BaseController { public static final String ENTITY_VIEW_ID = "entityViewId"; @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/entity-view/{entityViewId}", method = RequestMethod.GET) + @RequestMapping(value = "/entityView/{entityViewId}", method = RequestMethod.GET) @ResponseBody public EntityView getEntityViewById(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { @@ -66,7 +66,7 @@ public class EntityViewController extends BaseController { } @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/entity-view", method = RequestMethod.POST) + @RequestMapping(value = "/entityView", method = RequestMethod.POST) @ResponseBody public EntityView saveEntityView(@RequestBody EntityView entityView) throws ThingsboardException { try { @@ -86,7 +86,7 @@ public class EntityViewController extends BaseController { } @PreAuthorize("hasAuthority('TENANT_ADMIN')") - @RequestMapping(value = "/entity-view/{entityViewId}", method = RequestMethod.DELETE) + @RequestMapping(value = "/entityView/{entityViewId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) public void deleteEntityView(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { checkParameter(ENTITY_VIEW_ID, strEntityViewId); @@ -107,7 +107,7 @@ public class EntityViewController extends BaseController { } @PreAuthorize("hasAuthority('TENANT_ADMIN')") - @RequestMapping(value = "/customer/{customerId}/entity-view/{entityViewId}", method = RequestMethod.POST) + @RequestMapping(value = "/customer/{customerId}/entityView/{entityViewId}", method = RequestMethod.POST) @ResponseBody public EntityView assignEntityViewToCustomer(@PathVariable("customerId") String strCustomerId, @PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { @@ -136,7 +136,7 @@ public class EntityViewController extends BaseController { } @PreAuthorize("hasAuthority('TENANT_ADMIN')") - @RequestMapping(value = "/customer/entity-view/{entityViewId}", method = RequestMethod.DELETE) + @RequestMapping(value = "/customer/entityView/{entityViewId}", method = RequestMethod.DELETE) @ResponseBody public EntityView unassignEntityViewFromCustomer(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { checkParameter(ENTITY_VIEW_ID, strEntityViewId); @@ -164,7 +164,7 @@ public class EntityViewController extends BaseController { } @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/customer/{customerId}/entity-views", params = {"limit"}, method = RequestMethod.GET) + @RequestMapping(value = "/customer/{customerId}/entityViews", params = {"limit"}, method = RequestMethod.GET) @ResponseBody public TextPageData getCustomerEntityViews( @PathVariable("customerId") String strCustomerId, @@ -185,7 +185,7 @@ public class EntityViewController extends BaseController { } @PreAuthorize("hasAuthority('TENANT_ADMIN')") - @RequestMapping(value = "/tenant/entity-views", params = {"limit"}, method = RequestMethod.GET) + @RequestMapping(value = "/tenant/entityViews", params = {"limit"}, method = RequestMethod.GET) @ResponseBody public TextPageData getTenantEntityViews( @RequestParam int limit, @@ -202,7 +202,7 @@ public class EntityViewController extends BaseController { } @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/entity-views", method = RequestMethod.POST) + @RequestMapping(value = "/entityViews", method = RequestMethod.POST) @ResponseBody public List findByQuery(@RequestBody EntityViewSearchQuery query) throws ThingsboardException { checkNotNull(query); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index 920ce139cc..b3da7ad6e2 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -57,7 +57,6 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes Tenant tenant = new Tenant(); tenant.setTitle("My tenant"); savedTenant = doPost("/api/tenant", tenant, Tenant.class); - Assert.assertNotNull(savedTenant); tenantAdmin = new User(); @@ -93,15 +92,15 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes @Test public void testFindEntityViewById() throws Exception { - EntityView savedView = doPost("/api/entity-view", getNewEntityView("Test entity view"), EntityView.class); - EntityView foundView = doGet("/api/entity-view/" + savedView.getId().getId().toString(), EntityView.class); + EntityView savedView = doPost("/api/entityView", getNewEntityView("Test entity view"), EntityView.class); + EntityView foundView = doGet("/api/entityView/" + savedView.getId().getId().toString(), EntityView.class); Assert.assertNotNull(foundView); Assert.assertEquals(savedView, foundView); } @Test public void testSaveEntityView() throws Exception { - EntityView savedView = doPost("/api/entity-view", getNewEntityView("Test entity view"), EntityView.class); + EntityView savedView = doPost("/api/entityView", getNewEntityView("Test entity view"), EntityView.class); Assert.assertNotNull(savedView); Assert.assertNotNull(savedView.getId()); @@ -112,49 +111,49 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes Assert.assertEquals(savedView.getName(), savedView.getName()); savedView.setName("New test entity view"); - doPost("/api/entity-view", savedView, EntityView.class); - EntityView foundEntityView = doGet("/api/entity-view/" + savedView.getId().getId().toString(), EntityView.class); + doPost("/api/entityView", savedView, EntityView.class); + EntityView foundEntityView = doGet("/api/entityView/" + savedView.getId().getId().toString(), EntityView.class); Assert.assertEquals(foundEntityView.getName(), savedView.getName()); } @Test public void testDeleteEntityView() throws Exception { - EntityView savedView = doPost("/api/entity-view", getNewEntityView("Test entity view"), EntityView.class); - doDelete("/api/entity-view/" + savedView.getId().getId().toString()) + EntityView savedView = doPost("/api/entityView", getNewEntityView("Test entity view"), EntityView.class); + doDelete("/api/entityView/" + savedView.getId().getId().toString()) .andExpect(status().isOk()); - doGet("/api/entity-view/" + savedView.getId().getId().toString()) + doGet("/api/entityView/" + savedView.getId().getId().toString()) .andExpect(status().isNotFound()); } @Test public void testSaveEntityViewWithEmptyName() throws Exception { - doPost("/api/entity-view", getNewEntityView("Entity view")) + doPost("/api/entityView", getNewEntityView("")) .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString("Entity-view name should be specified"))); } @Test public void testAssignAndUnAssignedEntityViewToCustomer() throws Exception { - EntityView savedView = doPost("/api/entity-view", getNewEntityView("Test entity view"), EntityView.class); + EntityView savedView = doPost("/api/entityView", getNewEntityView("Test entity view"), EntityView.class); Customer savedCustomer = doPost("/api/customer", getNewCustomer("My customer"), Customer.class); EntityView assignedView = doPost("/api/customer/" + savedCustomer.getId().getId().toString() - + "/entity-view/" + savedView.getId().getId().toString(), EntityView.class); + + "/entityView/" + savedView.getId().getId().toString(), EntityView.class); Assert.assertEquals(savedCustomer.getId(), assignedView.getCustomerId()); - EntityView foundView = doGet("/api/entity-view" + savedView.getId().getId().toString(), EntityView.class); + EntityView foundView = doGet("/api/entityView" + savedView.getId().getId().toString(), EntityView.class); Assert.assertEquals(savedCustomer.getId(), foundView.getCustomerId()); - EntityView unAssignedView = doDelete("/api/customer/entity-view/" + savedView.getId().getId().toString(), EntityView.class); + EntityView unAssignedView = doDelete("/api/customer/entityView/" + savedView.getId().getId().toString(), EntityView.class); Assert.assertEquals(ModelConstants.NULL_UUID, unAssignedView.getCustomerId().getId()); - foundView = doGet("/api/entity-view/" + savedView.getId().getId().toString(), EntityView.class); + foundView = doGet("/api/entityView/" + savedView.getId().getId().toString(), EntityView.class); Assert.assertEquals(ModelConstants.NULL_UUID, foundView.getCustomerId().getId()); } @Test public void testAssignEntityViewToNonExistentCustomer() throws Exception { - EntityView savedView = doPost("/api/entity-view", getNewEntityView("Test entity view"), EntityView.class); + EntityView savedView = doPost("/api/entityView", getNewEntityView("Test entity view"), EntityView.class); doPost("/api/customer/" + UUIDs.timeBased().toString() + "/device/" + savedView.getId().getId().toString()) .andExpect(status().isNotFound()); } @@ -163,38 +162,43 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes public void testAssignEntityViewToCustomerFromDifferentTenant() throws Exception { loginSysAdmin(); - Tenant savedAnotherTenant = doPost("/api/tenant", getNewTenant("Different tenant"), Tenant.class); - Assert.assertNotNull(savedAnotherTenant); + Tenant tenant2 = getNewTenant("Different tenant"); + Tenant savedTenant2 = doPost("/api/tenant", tenant2, Tenant.class); + Assert.assertNotNull(savedTenant2); + + User tenantAdmin2 = new User(); + tenantAdmin2.setAuthority(Authority.TENANT_ADMIN); + tenantAdmin2.setTenantId(savedTenant2.getId()); + tenantAdmin2.setEmail("tenant3@thingsboard.org"); + tenantAdmin2.setFirstName("Joe"); + tenantAdmin2.setLastName("Downs"); + tenantAdmin2 = createUserAndLogin(tenantAdmin2, "testPassword1"); - User adminAnotherTenant = new User(); - adminAnotherTenant.setAuthority(Authority.TENANT_ADMIN); - adminAnotherTenant.setTenantId(savedAnotherTenant.getId()); - adminAnotherTenant.setEmail("tenant3@thingsboard.org"); - adminAnotherTenant.setFirstName("Joe"); - adminAnotherTenant.setLastName("Downs"); - createUserAndLogin(adminAnotherTenant, "testPassword1"); + Customer customer = getNewCustomer("Different customer"); + Customer savedCustomer = doPost("/api/customer", customer, Customer.class); - Customer savedCustomer = doPost("/api/customer", getNewCustomer("Different customer"), Customer.class); login(tenantAdmin.getEmail(), "testPassword1"); - EntityView savedView = doPost("/api/entity-view", getNewEntityView("Test entity view"), EntityView.class); - doPost("/api/customer/" + savedCustomer.getId().getId().toString() + "/entity-view/" + savedView.getId().getId().toString()) + EntityView view = getNewEntityView("Test entity view"); + EntityView savedView = doPost("/api/entityView", view, EntityView.class); + + doPost("/api/customer/" + savedCustomer.getId().getId().toString() + "/entityView/" + savedView.getId().getId().toString()) .andExpect(status().isForbidden()); loginSysAdmin(); - doDelete("/api/tenant/" + savedAnotherTenant.getId().getId().toString()) + doDelete("/api/tenant/" + savedTenant2.getId().getId().toString()) .andExpect(status().isOk()); } @Test public void testGetCustomerEntityViews() throws Exception { CustomerId customerId = doPost("/api/customer", getNewCustomer("Test customer"), Customer.class).getId(); - String urlTemplate = "/api/customer/" + customerId.getId().toString() + "/entity-views?"; + String urlTemplate = "/api/customer/" + customerId.getId().toString() + "/entityViews?"; List views = new ArrayList<>(); for (int i = 0; i < 128; i++) { - views.add(doPost("/api/customer/" + customerId.getId().toString() + "/entity-view/" + views.add(doPost("/api/customer/" + customerId.getId().toString() + "/entityView/" + getNewEntityView("Test entity view " + i).getId().getId().toString(), EntityView.class)); } @@ -209,11 +213,11 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes @Test public void testGetCustomerEntityViewsByName() throws Exception { CustomerId customerId = doPost("/api/customer", getNewCustomer("Test customer"), Customer.class).getId(); - String urlTemplate = "/api/customer/" + customerId.getId().toString() + "/entity-views?"; + String urlTemplate = "/api/customer/" + customerId.getId().toString() + "/entityViews?"; String name1 = "Entity view name1"; List namesOfView1 = fillListOf(125, name1, "/api/customer/" + customerId.getId().toString() - + "/entity-view/"); + + "/entityView/"); List loadedNamesOfView1 = loadListOf(new TextPageLink(15, name1), urlTemplate); Collections.sort(namesOfView1, idComparator); Collections.sort(loadedNamesOfView1, idComparator); @@ -221,14 +225,14 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes String name2 = "Entity view name2"; List NamesOfView2 = fillListOf(143, name2, "/api/customer/" + customerId.getId().toString() - + "/entity-view/"); + + "/entityView/"); List loadedNamesOfView2 = loadListOf(new TextPageLink(4, name2), urlTemplate); Collections.sort(NamesOfView2, idComparator); Collections.sort(loadedNamesOfView2, idComparator); Assert.assertEquals(NamesOfView2, loadedNamesOfView2); for (EntityView view : loadedNamesOfView1) { - doDelete("/api/customer/entity-view/" + view.getId().getId().toString()).andExpect(status().isOk()); + doDelete("/api/customer/entityView/" + view.getId().getId().toString()).andExpect(status().isOk()); } TextPageData pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference>(){}, new TextPageLink(4, name1)); @@ -236,7 +240,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes Assert.assertEquals(0, pageData.getData().size()); for (EntityView view : loadedNamesOfView2) { - doDelete("/api/customer/entity-view/" + view.getId().getId().toString()).andExpect(status().isOk()); + doDelete("/api/customer/entityView/" + view.getId().getId().toString()).andExpect(status().isOk()); } pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference>(){}, new TextPageLink(4, name2)); @@ -249,9 +253,9 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes List views = new ArrayList<>(); for (int i = 0; i < 178; i++) { - views.add(doPost("/api/entity-view/", getNewEntityView("Test entity view" + i), EntityView.class)); + views.add(doPost("/api/entityView/", getNewEntityView("Test entity view" + i), EntityView.class)); } - List loadedViews = loadListOf(new TextPageLink(23), "/api/tenant/entity-views?"); + List loadedViews = loadListOf(new TextPageLink(23), "/api/tenant/entityViews?"); Collections.sort(views, idComparator); Collections.sort(loadedViews, idComparator); @@ -263,30 +267,30 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes public void testGetTenantEntityViewsByName() throws Exception { String name1 = "Entity view name1"; List namesOfView1 = fillListOf(143, name1); - List loadedNamesOfView1 = loadListOf(new TextPageLink(15, name1), "/api/tenant/entity-views?"); + List loadedNamesOfView1 = loadListOf(new TextPageLink(15, name1), "/api/tenant/entityViews?"); Collections.sort(namesOfView1, idComparator); Collections.sort(loadedNamesOfView1, idComparator); Assert.assertEquals(namesOfView1, loadedNamesOfView1); String name2 = "Entity view name2"; List NamesOfView2 = fillListOf(75, name2); - List loadedNamesOfView2 = loadListOf(new TextPageLink(4, name2), "/api/tenant/entity-views?"); + List loadedNamesOfView2 = loadListOf(new TextPageLink(4, name2), "/api/tenant/entityViews?"); Collections.sort(NamesOfView2, idComparator); Collections.sort(loadedNamesOfView2, idComparator); Assert.assertEquals(NamesOfView2, loadedNamesOfView2); for (EntityView view : loadedNamesOfView1) { - doDelete("/api/entity-view/" + view.getId().getId().toString()).andExpect(status().isOk()); + doDelete("/api/entityView/" + view.getId().getId().toString()).andExpect(status().isOk()); } - TextPageData pageData = doGetTypedWithPageLink("/api/tenant/entity-views?", + TextPageData pageData = doGetTypedWithPageLink("/api/tenant/entityViews?", new TypeReference>(){}, new TextPageLink(4, name1)); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); for (EntityView view : loadedNamesOfView2) { - doDelete("/api/entity-view/" + view.getId().getId().toString()).andExpect(status().isOk()); + doDelete("/api/entityView/" + view.getId().getId().toString()).andExpect(status().isOk()); } - pageData = doGetTypedWithPageLink("/api/tenant/entity-views?", new TypeReference>(){}, + pageData = doGetTypedWithPageLink("/api/tenant/entityViews?", new TypeReference>(){}, new TextPageLink(4, name2)); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); @@ -298,7 +302,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes view.setEntityId(testDevice.getId()); view.setTenantId(savedTenant.getId()); view.setKeys(new TelemetryEntityView(obj)); - return doPost("/api/entity-view", view, EntityView.class); + return doPost("/api/entityView", view, EntityView.class); } private Customer getNewCustomer(String title) { @@ -326,7 +330,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes for (int i = 0; i < limit; i++) { String fullName = partOfName + ' ' + RandomStringUtils.randomAlphanumeric(15); fullName = i % 2 == 0 ? fullName.toLowerCase() : fullName.toUpperCase(); - viewNames.add(doPost("/api/entity-view", getNewEntityView(fullName), EntityView.class)); + viewNames.add(doPost("/api/entityView", getNewEntityView(fullName), EntityView.class)); } return viewNames; } From 7bfccc0f8b09e5d2063f88c9b92f16b84cc2577c Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 17 Sep 2018 17:27:37 +0300 Subject: [PATCH 087/118] Was fixed cache to pass tests --- .../server/dao/entityview/EntityViewServiceImpl.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) 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 54d8cc9981..c13261c003 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 @@ -51,6 +51,7 @@ import org.thingsboard.server.dao.tenant.TenantDao; import javax.annotation.Nullable; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.stream.Collectors; @@ -88,7 +89,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Autowired private CacheManager cacheManager; - @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId.getId()}") @Override public EntityView findEntityViewById(EntityViewId entityViewId) { log.trace("Executing findEntityViewById [{}]", entityViewId); @@ -105,7 +105,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti .orElse(null); } - @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityView.id, #entityView.tenantId, #entityView.name}") + @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityView.tenantId, #entityView.name}") @Override public EntityView saveEntityView(EntityView entityView) { log.trace("Executing save entity view [{}]", entityView); @@ -173,9 +173,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); deleteEntityRelations(entityViewId); EntityView entityView = entityViewDao.findById(entityViewId.getId()); - cache.evict(entityView.getId()); - cache.evict(entityView.getTenantId()); - cache.evict(entityView.getName()); + cache.evict(Arrays.asList(entityView.getTenantId(), entityView.getName())); entityViewDao.removeById(entityViewId.getId()); } @@ -310,9 +308,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Override protected void validateDataImpl(EntityView entityView) { - if (StringUtils.isEmpty(entityView.getKeys().toString())) { - throw new DataValidationException("Entity view type should be specified!"); - } if (StringUtils.isEmpty(entityView.getName())) { throw new DataValidationException("Entity view name should be specified!"); } From 825d7094b303640fa79cbe327fbe53994a9fc68c Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 17 Sep 2018 17:31:59 +0300 Subject: [PATCH 088/118] Was cleared of unnecessary --- .../org/thingsboard/server/dao/model/ModelConstants.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) 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 a6787d0520..83a89212d6 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 @@ -45,7 +45,6 @@ public class ModelConstants { public static final String SEARCH_TEXT_PROPERTY = "search_text"; public static final String ADDITIONAL_INFO_PROPERTY = "additional_info"; public static final String ENTITY_TYPE_PROPERTY = "entity_type"; - /*public static final String ENTITY_VIEW_ID_PROPERTY = "entity_view_id";*/ public static final String ENTITY_TYPE_COLUMN = ENTITY_TYPE_PROPERTY; public static final String ENTITY_ID_COLUMN = "entity_id"; @@ -53,7 +52,6 @@ public class ModelConstants { public static final String ATTRIBUTE_KEY_COLUMN = "attribute_key"; public static final String LAST_UPDATE_TS_COLUMN = "last_update_ts"; - /** * Cassandra user constants. */ @@ -148,12 +146,11 @@ public class ModelConstants { * Cassandra entityView constants. */ public static final String ENTITY_VIEW_TABLE_FAMILY_NAME = "entity_views"; - public static final String ENTITY_VIEW_FAMILY_NAME = "entity-view"; public static final String ENTITY_VIEW_ENTITY_ID_PROPERTY = ENTITY_ID_COLUMN; 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 = DEVICE_TYPE_PROPERTY; + public static final String ENTITY_VIEW_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "entity_view_by_customer_and_search_text"; 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_START_TS_PROPERTY = "start_ts"; From 72f0d90c90dca06b8f45bcc69595ff1d0349a2bd Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 17 Sep 2018 17:33:05 +0300 Subject: [PATCH 089/118] Was fixed the last tests --- .../BaseEntityViewControllerTest.java | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index b3da7ad6e2..5c62e6ad13 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -24,7 +24,6 @@ import org.junit.Before; import org.junit.Test; import org.thingsboard.server.common.data.*; import org.thingsboard.server.common.data.id.CustomerId; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.objects.AttributesEntityView; import org.thingsboard.server.common.data.objects.TelemetryEntityView; import org.thingsboard.server.common.data.page.TextPageData; @@ -33,11 +32,9 @@ import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.dao.model.ModelConstants; import java.util.*; -import java.util.stream.Stream; import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; public abstract class BaseEntityViewControllerTest extends AbstractControllerTest { @@ -54,9 +51,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes idComparator = new IdComparator<>(); - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - savedTenant = doPost("/api/tenant", tenant, Tenant.class); + savedTenant = doPost("/api/tenant", getNewTenant("My tenant"), Tenant.class); Assert.assertNotNull(savedTenant); tenantAdmin = new User(); @@ -119,29 +114,38 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes @Test public void testDeleteEntityView() throws Exception { - EntityView savedView = doPost("/api/entityView", getNewEntityView("Test entity view"), EntityView.class); + EntityView view = getNewEntityView("Test entity view"); + Customer customer = doPost("/api/customer", getNewCustomer("My customer"), Customer.class); + view.setCustomerId(customer.getId()); + EntityView savedView = doPost("/api/entityView", view, EntityView.class); + doDelete("/api/entityView/" + savedView.getId().getId().toString()) .andExpect(status().isOk()); + doGet("/api/entityView/" + savedView.getId().getId().toString()) .andExpect(status().isNotFound()); } @Test public void testSaveEntityViewWithEmptyName() throws Exception { - doPost("/api/entityView", getNewEntityView("")) + doPost("/api/entityView", new EntityView()) .andExpect(status().isBadRequest()) - .andExpect(statusReason(containsString("Entity-view name should be specified"))); + .andExpect(statusReason(containsString("Entity view name should be specified!"))); } @Test public void testAssignAndUnAssignedEntityViewToCustomer() throws Exception { - EntityView savedView = doPost("/api/entityView", getNewEntityView("Test entity view"), EntityView.class); + EntityView view = getNewEntityView("Test entity view"); Customer savedCustomer = doPost("/api/customer", getNewCustomer("My customer"), Customer.class); - EntityView assignedView = doPost("/api/customer/" + savedCustomer.getId().getId().toString() - + "/entityView/" + savedView.getId().getId().toString(), EntityView.class); + view.setCustomerId(savedCustomer.getId()); + EntityView savedView = doPost("/api/entityView", view, EntityView.class); + + EntityView assignedView = doPost( + "/api/customer/" + savedCustomer.getId().getId().toString() + "/entityView/" + savedView.getId().getId().toString(), + EntityView.class); Assert.assertEquals(savedCustomer.getId(), assignedView.getCustomerId()); - EntityView foundView = doGet("/api/entityView" + savedView.getId().getId().toString(), EntityView.class); + EntityView foundView = doGet("/api/entityView/" + savedView.getId().getId().toString(), EntityView.class); Assert.assertEquals(savedCustomer.getId(), foundView.getCustomerId()); EntityView unAssignedView = doDelete("/api/customer/entityView/" + savedView.getId().getId().toString(), EntityView.class); @@ -172,7 +176,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes tenantAdmin2.setEmail("tenant3@thingsboard.org"); tenantAdmin2.setFirstName("Joe"); tenantAdmin2.setLastName("Downs"); - tenantAdmin2 = createUserAndLogin(tenantAdmin2, "testPassword1"); + createUserAndLogin(tenantAdmin2, "testPassword1"); Customer customer = getNewCustomer("Different customer"); Customer savedCustomer = doPost("/api/customer", customer, Customer.class); @@ -298,9 +302,9 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes private EntityView getNewEntityView(String name) throws Exception { EntityView view = new EntityView(); - view.setName(name); view.setEntityId(testDevice.getId()); view.setTenantId(savedTenant.getId()); + view.setName(name); view.setKeys(new TelemetryEntityView(obj)); return doPost("/api/entityView", view, EntityView.class); } @@ -330,7 +334,10 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes for (int i = 0; i < limit; i++) { String fullName = partOfName + ' ' + RandomStringUtils.randomAlphanumeric(15); fullName = i % 2 == 0 ? fullName.toLowerCase() : fullName.toUpperCase(); - viewNames.add(doPost("/api/entityView", getNewEntityView(fullName), EntityView.class)); + EntityView view = getNewEntityView(fullName); + Customer customer = getNewCustomer("Test customer " + String.valueOf(Math.random())); + view.setCustomerId(doPost("/api/customer", customer, Customer.class).getId()); + viewNames.add(doPost("/api/entityView", view, EntityView.class)); } return viewNames; } From 9237a5dda9aa2cc5202efb58b73c0117aa3ae9b5 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 17 Sep 2018 17:43:42 +0300 Subject: [PATCH 090/118] Was deleted unnecessesary lines --- .../server/controller/EntityViewController.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) 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 b5adc327f5..26a48daff6 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java @@ -15,32 +15,28 @@ */ package org.thingsboard.server.controller; -import com.google.common.util.concurrent.ListenableFuture; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; 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.audit.ActionType; import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; import org.thingsboard.server.common.data.exception.ThingsboardException; 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.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.model.ModelConstants; -import org.thingsboard.server.service.security.model.SecurityUser; -import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; +import static org.thingsboard.server.controller.CustomerController.CUSTOMER_ID; + /** * Created by Victor Basanets on 8/28/2017. */ @@ -109,9 +105,9 @@ public class EntityViewController extends BaseController { @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/{customerId}/entityView/{entityViewId}", method = RequestMethod.POST) @ResponseBody - public EntityView assignEntityViewToCustomer(@PathVariable("customerId") String strCustomerId, + public EntityView assignEntityViewToCustomer(@PathVariable(CUSTOMER_ID) String strCustomerId, @PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { - checkParameter("customerId", strCustomerId); + checkParameter(CUSTOMER_ID, strCustomerId); checkParameter(ENTITY_VIEW_ID, strEntityViewId); try { CustomerId customerId = new CustomerId(toUUID(strCustomerId)); From 77de5522af9eaab7a6e3a60e0d504f3a8b04aac5 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 17 Sep 2018 19:54:34 +0300 Subject: [PATCH 091/118] Were fixed materialized views --- .../main/data/upgrade/2.1.1/schema_update.cql | 105 +++++++----------- dao/src/main/resources/cassandra/schema.cql | 31 ++++-- 2 files changed, 61 insertions(+), 75 deletions(-) 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 e0cff4108f..c5d919bc7c 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 @@ -22,72 +22,51 @@ DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_views_by_tenant_and_customer 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, - keys text, - start_ts bigint, - end_ts bigint, - search_text text, - additional_info text, - PRIMARY KEY (id, entity_id, tenant_id, customer_id) +id timeuuid, +entity_id timeuuid, +entity_type text, +tenant_id timeuuid, +customer_id timeuuid, +name text, +keys text, +start_ts bigint, +end_ts bigint, +search_text text, +additional_info text, +PRIMARY KEY (id, tenant_id, customer_id) ); CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_name AS - SELECT * - from thingsboard.entity_views - WHERE entity_id IS NOT NULL - AND tenant_id IS NOT NULL - AND customer_id IS NOT NULL - AND keys IS NOT NULL - AND start_ts IS NOT NULL - AND end_ts IS NOT NULL - AND name IS NOT NULL - AND id IS NOT NULL - PRIMARY KEY (tenant_id, name, id, entity_id, customer_id) - WITH CLUSTERING ORDER BY (name ASC, id DESC, entity_id DESC, customer_id DESC); +SELECT * +from thingsboard.entity_views +WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL +PRIMARY KEY (tenant_id, name, id, entity_id, customer_id) +WITH CLUSTERING ORDER BY (name ASC, id DESC, entity_id DESC, customer_id DESC); -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_entity AS - SELECT * - from thingsboard.entity_views - WHERE entity_id IS NOT NULL - AND tenant_id IS NOT NULL - AND customer_id IS NOT NULL - AND keys IS NOT NULL - AND start_ts IS NOT NULL - AND end_ts IS NOT NULL - AND name IS NOT NULL - AND id IS NOT NULL - PRIMARY KEY (tenant_id, entity_id, id, customer_id, name) - WITH CLUSTERING ORDER BY (entity_id ASC, customer_id ASC, id DESC, name DESC); +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_search_text AS +SELECT * +from thingsboard.entity_views +WHERE entity_id IS NOT NULL AND search_text IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL +PRIMARY KEY (tenant_id, search_text, id, customer_id, name) +WITH CLUSTERING ORDER BY (search_text ASC, customer_id ASC, id DESC, name DESC); -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer AS - SELECT * - from thingsboard.entity_views - WHERE entity_id IS NOT NULL - AND tenant_id IS NOT NULL - AND customer_id IS NOT NULL - AND keys IS NOT NULL - AND start_ts IS NOT NULL - AND end_ts IS NOT NULL - AND name IS NOT NULL - AND id IS NOT NULL - PRIMARY KEY (tenant_id, customer_id, id, entity_id, name) - WITH CLUSTERING ORDER BY (customer_id ASC, id DESC, entity_id DESC, name DESC); +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_entity_and_search_text AS +SELECT * +from thingsboard.entity_views +WHERE entity_id IS NOT NULL AND search_text IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL +PRIMARY KEY (tenant_id, entity_id, search_text, id, customer_id, name) +WITH CLUSTERING ORDER BY (entity_id ASC, search_text ASC, id DESC, name DESC); -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer_and_entity AS - SELECT * - from thingsboard.entity_views - WHERE entity_id IS NOT NULL - AND tenant_id IS NOT NULL - AND customer_id IS NOT NULL - AND keys IS NOT NULL - AND start_ts IS NOT NULL - AND end_ts IS NOT NULL - AND name IS NOT NULL - AND id IS NOT NULL - PRIMARY KEY (tenant_id, customer_id, entity_id, id, name) - WITH CLUSTERING ORDER BY (customer_id ASC, entity_id DESC, id DESC, name DESC); +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer_and_search_text AS +SELECT * +from thingsboard.entity_views +WHERE entity_id IS NOT NULL AND search_text IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL +PRIMARY KEY (tenant_id, customer_id, search_text, id, entity_id) +WITH CLUSTERING ORDER BY (customer_id ASC, search_text ASC, id DESC, entity_id DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer_and_entity_and_search_text AS +SELECT * +from thingsboard.entity_views +WHERE entity_id IS NOT NULL AND search_text IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL +PRIMARY KEY (tenant_id, customer_id, search_text,entity_id, id) +WITH CLUSTERING ORDER BY (customer_id ASC, search_text ASC, entity_id DESC, id DESC); diff --git a/dao/src/main/resources/cassandra/schema.cql b/dao/src/main/resources/cassandra/schema.cql index 3cefacb970..674d30e824 100644 --- a/dao/src/main/resources/cassandra/schema.cql +++ b/dao/src/main/resources/cassandra/schema.cql @@ -661,23 +661,30 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_na PRIMARY KEY (tenant_id, name, id, entity_id, customer_id) WITH CLUSTERING ORDER BY (name ASC, id DESC, entity_id DESC, customer_id DESC); -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_entity AS +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_search_text AS SELECT * from thingsboard.entity_views - WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL - PRIMARY KEY (tenant_id, entity_id, id, customer_id, name) - WITH CLUSTERING ORDER BY (entity_id ASC, customer_id ASC, id DESC, name DESC); + WHERE entity_id IS NOT NULL AND search_text IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL + PRIMARY KEY (tenant_id, search_text, id, customer_id, name) + WITH CLUSTERING ORDER BY (search_text ASC, customer_id ASC, id DESC, name DESC); -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer AS +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_entity_and_search_text AS SELECT * from thingsboard.entity_views - WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL - PRIMARY KEY (tenant_id, customer_id, id, entity_id, name) - WITH CLUSTERING ORDER BY (customer_id ASC, id DESC, entity_id DESC, name DESC); + WHERE entity_id IS NOT NULL AND search_text IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL + PRIMARY KEY (tenant_id, entity_id, search_text, id, customer_id, name) + WITH CLUSTERING ORDER BY (entity_id ASC, search_text ASC, id DESC, name DESC); -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer_and_entity AS +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer_and_search_text AS SELECT * from thingsboard.entity_views - WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL - PRIMARY KEY (tenant_id, customer_id, entity_id, id, name) - WITH CLUSTERING ORDER BY (customer_id ASC, entity_id DESC, id DESC, name DESC); + WHERE entity_id IS NOT NULL AND search_text IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL + PRIMARY KEY (tenant_id, customer_id, search_text, id, entity_id) + WITH CLUSTERING ORDER BY (customer_id ASC, search_text ASC, id DESC, entity_id DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer_and_entity_and_search_text AS + SELECT * + from thingsboard.entity_views + WHERE entity_id IS NOT NULL AND search_text IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL + PRIMARY KEY (tenant_id, customer_id, search_text,entity_id, id) + WITH CLUSTERING ORDER BY (customer_id ASC, search_text ASC, entity_id DESC, id DESC); From d3ba64683c53c81c341976cb993f37e7bf354fd6 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 17 Sep 2018 19:56:17 +0300 Subject: [PATCH 092/118] Were added all necessary methods --- .../entityview/CassandraEntityViewDao.java | 68 +++++++++++++------ .../server/dao/model/ModelConstants.java | 6 +- 2 files changed, 51 insertions(+), 23 deletions(-) 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 5de34e4b71..98f6105646 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 @@ -67,49 +67,75 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao findEntityViewByTenantId(UUID tenantId, TextPageLink pageLink) { - log.debug("Try to find entity-views by tenantId [{}] and pageLink [{}]", tenantId, pageLink); + log.debug("Try to find entity views by tenantId [{}] and pageLink [{}]", tenantId, pageLink); List 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); + Collections.singletonList(eq(TENANT_ID_PROPERTY, tenantId)), pageLink); + log.trace("Found entity views [{}] by tenantId [{}] and pageLink [{}]", + entityViewEntities, tenantId, pageLink); return DaoUtil.convertDataList(entityViewEntities); } @Override - public Optional 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)))) - ); + public Optional findEntityViewByTenantIdAndName(UUID tenantId, String name) { + Select.Where query = select().from(ENTITY_VIEW_BY_TENANT_AND_NAME).where(); + query.and(eq(ENTITY_VIEW_TENANT_ID_PROPERTY, tenantId)); + query.and(eq(ENTITY_VIEW_NAME_PROPERTY, name)); + return Optional.ofNullable(DaoUtil.getData(findOneByStatement(query))); } @Override public List findEntityViewByTenantIdAndEntityId(UUID tenantId, UUID entityId, TextPageLink pageLink) { - log.debug("Try to find entity-views by tenantId [{}], entityId[{}] and pageLink [{}]", tenantId, entityId, pageLink); - List 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)), + log.debug("Try to find entity views by tenantId [{}], entityId [{}] and pageLink [{}]", + tenantId, entityId, pageLink); + List entityViewEntities = findPageWithTextSearch( + ENTITY_VIEW_BY_TENANT_AND_ENTITY_AND_SEARCH_TEXT, + Arrays.asList(eq(CUSTOMER_ID_PROPERTY, entityId), eq(TENANT_ID_PROPERTY, tenantId)), pageLink); - - log.trace("Found entity-views [{}] by tenantId [{}], entityId [{}] and pageLink [{}]", entityViewEntities, tenantId, entityId, pageLink); + log.trace("Found entity views [{}] by tenantId [{}], entityId [{}] and pageLink [{}]", + entityViewEntities, tenantId, entityId, pageLink); return DaoUtil.convertDataList(entityViewEntities); } @Override public List findEntityViewsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) { - return null; + log.debug("Try to find entity views by tenantId [{}], customerId[{}] and pageLink [{}]", + tenantId, customerId, pageLink); + List entityViewEntities = findPageWithTextSearch( + ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_SEARCH_TEXT, + 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); } @Override - public List findEntityViewsByTenantIdAndCustomerIdAndEntityId(UUID tenantId, UUID customerId, UUID entityId, TextPageLink pageLink) { - return null; + public List findEntityViewsByTenantIdAndCustomerIdAndEntityId(UUID tenantId, + UUID customerId, + UUID entityId, + TextPageLink pageLink) { + + log.debug("Try to find entity views by tenantId [{}], customerId [{}], entityId [{}] and pageLink [{}]", + tenantId, customerId, entityId, pageLink); + List entityViewEntities = findPageWithTextSearch( + ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_ENTITY_AND_SEARCH_TEXT, + Arrays.asList( + eq(TENANT_ID_PROPERTY, tenantId), + eq(CUSTOMER_ID_PROPERTY, customerId), + eq(ENTITY_ID_COLUMN, entityId)), + pageLink); + log.trace("Found devices [{}] by tenantId [{}], customerId [{}], entityId [{}] and pageLink [{}]", + entityViewEntities, tenantId, customerId, entityId, pageLink); + return DaoUtil.convertDataList(entityViewEntities); } @Override public ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(UUID tenantId, UUID entityId) { - // TODO: implement this - return null; + log.debug("Try to find entity views by tenantId [{}] and entityId [{}]", tenantId, entityId); + Select.Where query = select().from(getColumnFamilyName()).where(); + query.and(eq(TENANT_ID_PROPERTY, tenantId)); + query.and(eq(ENTITY_ID_COLUMN, entityId)); + return findListByStatementAsync(query); } } 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 83a89212d6..da180af3a9 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 @@ -150,13 +150,15 @@ 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_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "entity_view_by_customer_and_search_text"; - public static final String ENTITY_VIEW_TENANT_AND_NAME_VIEW_NAME = "entity_view_by_tenant_and_name"; + public static final String ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_ENTITY_AND_SEARCH_TEXT = "entity_views_by_tenant_and_customer_and_entity_and_search_text"; + public static final String ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_SEARCH_TEXT = "entity_views_by_tenant_and_customer_and_search_text"; public static final String ENTITY_VIEW_KEYS_PROPERTY = "keys"; public static final String ENTITY_VIEW_START_TS_PROPERTY = "start_ts"; public static final String ENTITY_VIEW_END_TS_PROPERTY = "end_ts"; 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"; + public static final String ENTITY_VIEW_BY_TENANT_AND_NAME = "entity_views_by_tenant_and_name"; + public static final String ENTITY_VIEW_BY_TENANT_AND_ENTITY_AND_SEARCH_TEXT = "entity_view_by_tenant_and_entity_and_search_text"; /** * Cassandra audit log constants. From 1e6bd5513089a2e3c3b3aaf1de5c2d282a512ffe Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Tue, 18 Sep 2018 15:33:37 +0300 Subject: [PATCH 093/118] Was fixed Materialized View --- .../main/data/upgrade/2.1.1/schema_update.cql | 100 +++++++++++------- .../server/dao/model/ModelConstants.java | 6 +- dao/src/main/resources/cassandra/schema.cql | 90 +++++++++++----- 3 files changed, 128 insertions(+), 68 deletions(-) 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 c5d919bc7c..888f43c5ad 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 @@ -22,51 +22,71 @@ DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_views_by_tenant_and_customer 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, -keys text, -start_ts bigint, -end_ts bigint, -search_text text, -additional_info text, -PRIMARY KEY (id, tenant_id, customer_id) + id timeuuid, + entity_id timeuuid, + entity_type text, + tenant_id timeuuid, + customer_id timeuuid, + name text, + keys text, + start_ts bigint, + end_ts bigint, + 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 * -from thingsboard.entity_views -WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL -PRIMARY KEY (tenant_id, name, id, entity_id, customer_id) -WITH CLUSTERING ORDER BY (name ASC, id DESC, entity_id DESC, customer_id DESC); + SELECT * + from thingsboard.entity_views + WHERE tenant_id IS NOT NULL + AND entity_id IS NOT NULL + AND customer_id IS NOT NULL + AND name IS NOT NULL + AND id IS NOT NULL + PRIMARY KEY (tenant_id, name, id, customer_id, entity_id) + WITH CLUSTERING ORDER BY (name ASC, id DESC, customer_id DESC); CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_search_text AS -SELECT * -from thingsboard.entity_views -WHERE entity_id IS NOT NULL AND search_text IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL -PRIMARY KEY (tenant_id, search_text, id, customer_id, name) -WITH CLUSTERING ORDER BY (search_text ASC, customer_id ASC, id DESC, name DESC); + SELECT * + from thingsboard.entity_views + WHERE tenant_id IS NOT NULL + AND entity_id IS NOT NULL + AND customer_id IS NOT NULL + AND search_text IS NOT NULL + AND id IS NOT NULL + PRIMARY KEY (tenant_id, search_text, id, customer_id, entity_id) + WITH CLUSTERING ORDER BY (search_text ASC, id DESC, customer_id DESC); -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_entity_and_search_text AS -SELECT * -from thingsboard.entity_views -WHERE entity_id IS NOT NULL AND search_text IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL -PRIMARY KEY (tenant_id, entity_id, search_text, id, customer_id, name) -WITH CLUSTERING ORDER BY (entity_id ASC, search_text ASC, id DESC, name DESC); +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_entity AS + SELECT * + from thingsboard.entity_views + WHERE tenant_id IS NOT NULL + AND customer_id IS NOT NULL + AND entity_id IS NOT NULL + AND search_text IS NOT NULL + AND id IS NOT NULL + PRIMARY KEY (tenant_id, entity_id, search_text, id, customer_id) + WITH CLUSTERING ORDER BY (entity_id ASC, search_text ASC, id DESC, customer_id DESC); -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer_and_search_text AS -SELECT * -from thingsboard.entity_views -WHERE entity_id IS NOT NULL AND search_text IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL -PRIMARY KEY (tenant_id, customer_id, search_text, id, entity_id) -WITH CLUSTERING ORDER BY (customer_id ASC, search_text ASC, id DESC, entity_id DESC); +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer AS + SELECT * + from thingsboard.entity_views + WHERE tenant_id IS NOT NULL + AND customer_id IS NOT NULL + AND entity_id IS NOT NULL + AND search_text IS NOT NULL + AND id IS NOT NULL + PRIMARY KEY (tenant_id, customer_id, search_text, id, entity_id) + WITH CLUSTERING ORDER BY (customer_id DESC, search_text ASC, id DESC); -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer_and_entity_and_search_text AS -SELECT * -from thingsboard.entity_views -WHERE entity_id IS NOT NULL AND search_text IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL -PRIMARY KEY (tenant_id, customer_id, search_text,entity_id, id) -WITH CLUSTERING ORDER BY (customer_id ASC, search_text ASC, entity_id DESC, id DESC); +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer_and_entity AS + SELECT * + from thingsboard.entity_views + WHERE tenant_id IS NOT NULL + AND customer_id IS NOT NULL + AND entity_id IS NOT NULL + AND search_text IS NOT NULL + AND id IS NOT NULL + PRIMARY KEY (tenant_id, customer_id, entity_id, search_text, id) + WITH CLUSTERING ORDER BY (customer_id DESC, entity_id ASC, search_text ASC, id DESC); 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 da180af3a9..45d0ff9493 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 @@ -150,15 +150,15 @@ 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_BY_TENANT_AND_CUSTOMER_AND_ENTITY_AND_SEARCH_TEXT = "entity_views_by_tenant_and_customer_and_entity_and_search_text"; - public static final String ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_SEARCH_TEXT = "entity_views_by_tenant_and_customer_and_search_text"; + public static final String ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_ENTITY_AND_SEARCH_TEXT = "entity_views_by_tenant_and_customer_and_entity"; + public static final String ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_SEARCH_TEXT = "entity_views_by_tenant_and_customer"; public static final String ENTITY_VIEW_KEYS_PROPERTY = "keys"; public static final String ENTITY_VIEW_START_TS_PROPERTY = "start_ts"; public static final String ENTITY_VIEW_END_TS_PROPERTY = "end_ts"; 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"; public static final String ENTITY_VIEW_BY_TENANT_AND_NAME = "entity_views_by_tenant_and_name"; - public static final String ENTITY_VIEW_BY_TENANT_AND_ENTITY_AND_SEARCH_TEXT = "entity_view_by_tenant_and_entity_and_search_text"; + public static final String ENTITY_VIEW_BY_TENANT_AND_ENTITY_AND_SEARCH_TEXT = "entity_view_by_tenant_and_entity"; /** * Cassandra audit log constants. diff --git a/dao/src/main/resources/cassandra/schema.cql b/dao/src/main/resources/cassandra/schema.cql index 674d30e824..4645420eb8 100644 --- a/dao/src/main/resources/cassandra/schema.cql +++ b/dao/src/main/resources/cassandra/schema.cql @@ -165,35 +165,55 @@ CREATE TABLE IF NOT EXISTS thingsboard.device ( CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_tenant_and_name AS SELECT * from thingsboard.device - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL + WHERE tenant_id IS NOT NULL + AND customer_id IS NOT NULL + AND type IS NOT NULL + AND name IS NOT NULL + AND id IS NOT NULL PRIMARY KEY ( tenant_id, name, id, customer_id, type) WITH CLUSTERING ORDER BY ( name ASC, id DESC, customer_id DESC); CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_tenant_and_search_text AS SELECT * from thingsboard.device - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + WHERE tenant_id IS NOT NULL + AND customer_id IS NOT NULL + AND type IS NOT NULL + AND search_text IS NOT NULL + AND id IS NOT NULL PRIMARY KEY ( tenant_id, search_text, id, customer_id, type) WITH CLUSTERING ORDER BY ( search_text ASC, id DESC, customer_id DESC); CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_tenant_by_type_and_search_text AS SELECT * from thingsboard.device - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + WHERE tenant_id IS NOT NULL + AND customer_id IS NOT NULL + AND type IS NOT NULL + AND search_text IS NOT NULL + AND id IS NOT NULL PRIMARY KEY ( tenant_id, type, search_text, id, customer_id) WITH CLUSTERING ORDER BY ( type ASC, search_text ASC, id DESC, customer_id DESC); CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_customer_and_search_text AS SELECT * from thingsboard.device - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + WHERE tenant_id IS NOT NULL + AND customer_id IS NOT NULL + AND type IS NOT NULL + AND search_text IS NOT NULL + AND id IS NOT NULL PRIMARY KEY ( customer_id, tenant_id, search_text, id, type ) WITH CLUSTERING ORDER BY ( tenant_id DESC, search_text ASC, id DESC ); CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_customer_by_type_and_search_text AS SELECT * from thingsboard.device - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL + WHERE tenant_id IS NOT NULL + AND customer_id IS NOT NULL + AND type IS NOT NULL + AND search_text IS NOT NULL + AND id IS NOT NULL PRIMARY KEY ( customer_id, tenant_id, type, search_text, id ) WITH CLUSTERING ORDER BY ( tenant_id DESC, type ASC, search_text ASC, id DESC ); @@ -651,40 +671,60 @@ CREATE TABLE IF NOT EXISTS thingsboard.entity_views ( end_ts bigint, search_text text, additional_info text, - PRIMARY KEY (id, tenant_id, customer_id) + PRIMARY KEY (id, entity_id, tenant_id, customer_id) ); CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_name AS SELECT * from thingsboard.entity_views - WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL - PRIMARY KEY (tenant_id, name, id, entity_id, customer_id) - WITH CLUSTERING ORDER BY (name ASC, id DESC, entity_id DESC, customer_id DESC); + WHERE tenant_id IS NOT NULL + AND entity_id IS NOT NULL + AND customer_id IS NOT NULL + AND name IS NOT NULL + AND id IS NOT NULL + PRIMARY KEY (tenant_id, name, id, customer_id, entity_id) + WITH CLUSTERING ORDER BY (name ASC, id DESC, customer_id DESC); CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_search_text AS SELECT * from thingsboard.entity_views - WHERE entity_id IS NOT NULL AND search_text IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL - PRIMARY KEY (tenant_id, search_text, id, customer_id, name) - WITH CLUSTERING ORDER BY (search_text ASC, customer_id ASC, id DESC, name DESC); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_entity_and_search_text AS + WHERE tenant_id IS NOT NULL + AND entity_id IS NOT NULL + AND customer_id IS NOT NULL + AND search_text IS NOT NULL + AND id IS NOT NULL + PRIMARY KEY (tenant_id, search_text, id, customer_id, entity_id) + WITH CLUSTERING ORDER BY (search_text ASC, id DESC, customer_id DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_entity AS SELECT * from thingsboard.entity_views - WHERE entity_id IS NOT NULL AND search_text IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL - PRIMARY KEY (tenant_id, entity_id, search_text, id, customer_id, name) - WITH CLUSTERING ORDER BY (entity_id ASC, search_text ASC, id DESC, name DESC); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer_and_search_text AS + WHERE tenant_id IS NOT NULL + AND customer_id IS NOT NULL + AND entity_id IS NOT NULL + AND search_text IS NOT NULL + AND id IS NOT NULL + PRIMARY KEY (tenant_id, entity_id, search_text, id, customer_id) + WITH CLUSTERING ORDER BY (entity_id ASC, search_text ASC, id DESC, customer_id DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer AS SELECT * from thingsboard.entity_views - WHERE entity_id IS NOT NULL AND search_text IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL + WHERE tenant_id IS NOT NULL + AND customer_id IS NOT NULL + AND entity_id IS NOT NULL + AND search_text IS NOT NULL + AND id IS NOT NULL PRIMARY KEY (tenant_id, customer_id, search_text, id, entity_id) - WITH CLUSTERING ORDER BY (customer_id ASC, search_text ASC, id DESC, entity_id DESC); + WITH CLUSTERING ORDER BY (customer_id DESC, search_text ASC, id DESC); -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer_and_entity_and_search_text AS +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer_and_entity AS SELECT * from thingsboard.entity_views - WHERE entity_id IS NOT NULL AND search_text IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL - PRIMARY KEY (tenant_id, customer_id, search_text,entity_id, id) - WITH CLUSTERING ORDER BY (customer_id ASC, search_text ASC, entity_id DESC, id DESC); + WHERE tenant_id IS NOT NULL + AND customer_id IS NOT NULL + AND entity_id IS NOT NULL + AND search_text IS NOT NULL + AND id IS NOT NULL + PRIMARY KEY (tenant_id, customer_id, entity_id, search_text, id) + WITH CLUSTERING ORDER BY (customer_id DESC, entity_id ASC, search_text ASC, id DESC); From 4182a70d5fcf8f5530a3de39a303218fa2c3d855 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 18 Sep 2018 19:42:14 +0300 Subject: [PATCH 094/118] Fixes for subscription --- .../DefaultTelemetrySubscriptionService.java | 56 +++++++++++++++++-- .../service/telemetry/sub/Subscription.java | 4 -- 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java index 3ded8827fb..617cd20f88 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.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, @@ -68,6 +68,7 @@ import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -140,24 +141,64 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio @Override public void addLocalWsSubscription(String sessionId, EntityId entityId, SubscriptionState sub) { + long startTime = 0L; + long endTime = 0L; if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) { EntityView entityView = entityViewService.findEntityViewById(new EntityViewId(entityId.getId())); entityId = entityView.getEntityId(); + startTime = entityView.getStartTimeMs(); + endTime = entityView.getEndTimeMs(); + sub = getUpdatedSubscriptionState(entityId, sub, entityView); } Optional server = routingService.resolveById(entityId); Subscription subscription; if (server.isPresent()) { ServerAddress address = server.get(); log.trace("[{}] Forwarding subscription [{}] for [{}] entity [{}] to [{}]", sessionId, sub.getSubscriptionId(), entityId.getEntityType().name(), entityId, address); - subscription = new Subscription(sub, true, address); + subscription = new Subscription(sub, true, address, startTime, endTime); tellNewSubscription(address, sessionId, subscription); } else { log.trace("[{}] Registering local subscription [{}] for [{}] entity [{}]", sessionId, sub.getSubscriptionId(), entityId.getEntityType().name(), entityId); - subscription = new Subscription(sub, true); + subscription = new Subscription(sub, true, null, startTime, endTime); } registerSubscription(sessionId, entityId, subscription); } + private SubscriptionState getUpdatedSubscriptionState(EntityId entityId, SubscriptionState sub, EntityView entityView) { + boolean allKeys; + Map keyStates; + if (sub.getType().equals(TelemetryFeature.TIMESERIES) && !entityView.getKeys().getTimeseries().isEmpty()) { + allKeys = false; + keyStates = sub.getKeyStates().entrySet() + .stream().filter(entry -> entityView.getKeys().getTimeseries().contains(entry.getKey())) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } else if (sub.getType().equals(TelemetryFeature.ATTRIBUTES)) { + if (sub.getScope().equals(DataConstants.CLIENT_SCOPE) && !entityView.getKeys().getAttributes().getCs().isEmpty()) { + allKeys = false; + keyStates = filterMap(sub, entityView.getKeys().getAttributes().getCs()); + } else if (sub.getScope().equals(DataConstants.SERVER_SCOPE) && !entityView.getKeys().getAttributes().getSs().isEmpty()) { + allKeys = false; + keyStates = filterMap(sub, entityView.getKeys().getAttributes().getSs()); + } else if (sub.getScope().equals(DataConstants.SERVER_SCOPE) && !entityView.getKeys().getAttributes().getSh().isEmpty()) { + allKeys = false; + keyStates = filterMap(sub, entityView.getKeys().getAttributes().getSh()); + } else { + allKeys = sub.isAllKeys(); + keyStates = sub.getKeyStates(); + } + } else { + allKeys = sub.isAllKeys(); + keyStates = sub.getKeyStates(); + } + return new SubscriptionState(sub.getWsSessionId(), sub.getSubscriptionId(), entityId, sub.getType(), allKeys, keyStates, sub.getScope()); + } + + private Map filterMap(SubscriptionState sub, List allowedKeys) { + return sub.getKeyStates().entrySet() + .stream().filter(entry -> allowedKeys.contains(entry.getKey())) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + @Override public void cleanupLocalWsSessionSubscriptions(TelemetryWebSocketSessionRef sessionRef, String sessionId) { cleanupLocalWsSessionSubscriptions(sessionId); @@ -426,7 +467,7 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio onLocalSubUpdate(entityId, s -> TelemetryFeature.ATTRIBUTES == s.getType() && (StringUtils.isEmpty(s.getScope()) || scope.equals(s.getScope())), s -> { List subscriptionUpdate = null; for (AttributeKvEntry kv : attributes) { - if (s.isAllKeys() || s.getKeyStates().containsKey(kv.getKey())) { + if (isInTimeRange(s, kv.getLastUpdateTs()) && (s.isAllKeys() || s.getKeyStates().containsKey(kv.getKey()))) { if (subscriptionUpdate == null) { subscriptionUpdate = new ArrayList<>(); } @@ -441,7 +482,7 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio onLocalSubUpdate(entityId, s -> TelemetryFeature.TIMESERIES == s.getType(), s -> { List subscriptionUpdate = null; for (TsKvEntry kv : ts) { - if (s.isAllKeys() || s.getKeyStates().containsKey((kv.getKey()))) { + if (isInTimeRange(s, kv.getTs()) && (s.isAllKeys() || s.getKeyStates().containsKey((kv.getKey())))) { if (subscriptionUpdate == null) { subscriptionUpdate = new ArrayList<>(); } @@ -452,6 +493,11 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio }); } + private boolean isInTimeRange(Subscription subscription, long kvTime) { + return (subscription.getStartTime() == 0 || subscription.getStartTime() <= kvTime) + && (subscription.getEndTime() == 0 || subscription.getEndTime() >= kvTime); + } + private void onLocalSubUpdate(EntityId entityId, Predicate filter, Function> f) { Set deviceSubscriptions = subscriptionsByEntityId.get(entityId); if (deviceSubscriptions != null) { diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/sub/Subscription.java b/application/src/main/java/org/thingsboard/server/service/telemetry/sub/Subscription.java index 47c80e9aa6..32d6243a61 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/sub/Subscription.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/sub/Subscription.java @@ -33,10 +33,6 @@ public class Subscription { private long startTime; private long endTime; - public Subscription(SubscriptionState sub, boolean local) { - this(sub, local, null); - } - public Subscription(SubscriptionState sub, boolean local, ServerAddress server) { this(sub, local, server, 0L, 0L); } From 531a16cd1223ef903a98261ddc8cd912f7dbb20b Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 18 Sep 2018 22:21:39 +0300 Subject: [PATCH 095/118] Fixes for subscription --- .../service/telemetry/DefaultTelemetrySubscriptionService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java index 617cd20f88..fb9a160a2c 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.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, From b40b8c8e9f720a92fe00ff55f0d2341710726463 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 18 Sep 2018 23:00:27 +0300 Subject: [PATCH 096/118] Code review fixes --- .../main/data/upgrade/2.1.1/schema_update.cql | 33 ++----------- .../install/ThingsboardInstallService.java | 2 - .../install/DefaultDataUpdateService.java | 4 -- .../service/security/AccessValidator.java | 10 +++- .../BaseEntityViewControllerTest.java | 44 ++++++++++------- .../server/common/data/EntityView.java | 4 +- .../dao/customer/CustomerServiceImpl.java | 5 ++ .../entityview/CassandraEntityViewDao.java | 49 ++++++------------- .../server/dao/entityview/EntityViewDao.java | 25 ---------- .../dao/entityview/EntityViewService.java | 22 ++------- .../dao/entityview/EntityViewServiceImpl.java | 48 +----------------- .../server/dao/model/ModelConstants.java | 6 +-- .../dao/model/nosql/EntityViewEntity.java | 11 +++-- .../dao/model/sql/EntityViewEntity.java | 17 +++++-- .../sql/entityview/EntityViewRepository.java | 28 ----------- .../dao/sql/entityview/JpaEntityViewDao.java | 31 +----------- .../server/dao/tenant/TenantServiceImpl.java | 5 ++ dao/src/main/resources/cassandra/schema.cql | 26 +--------- .../test/resources/sql/drop-all-tables.sql | 2 +- 19 files changed, 102 insertions(+), 270 deletions(-) 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 888f43c5ad..a633634f60 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 @@ -14,10 +14,9 @@ -- limitations under the License. -- -DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_views_by_tenant_and_name; -DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_views_by_tenant_and_entity; -DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_views_by_tenant_and_customer; -DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_views_by_tenant_and_customer_and_entity; +DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_name; +DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_search_text; +DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_customer; DROP TABLE IF EXISTS thingsboard.entity_views; @@ -36,7 +35,7 @@ CREATE TABLE IF NOT EXISTS thingsboard.entity_views ( PRIMARY KEY (id, entity_id, tenant_id, customer_id) ); -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_name AS +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_name AS SELECT * from thingsboard.entity_views WHERE tenant_id IS NOT NULL @@ -58,18 +57,7 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_sea PRIMARY KEY (tenant_id, search_text, id, customer_id, entity_id) WITH CLUSTERING ORDER BY (search_text ASC, id DESC, customer_id DESC); -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_entity AS - SELECT * - from thingsboard.entity_views - WHERE tenant_id IS NOT NULL - AND customer_id IS NOT NULL - AND entity_id IS NOT NULL - AND search_text IS NOT NULL - AND id IS NOT NULL - PRIMARY KEY (tenant_id, entity_id, search_text, id, customer_id) - WITH CLUSTERING ORDER BY (entity_id ASC, search_text ASC, id DESC, customer_id DESC); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer AS +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_customer AS SELECT * from thingsboard.entity_views WHERE tenant_id IS NOT NULL @@ -79,14 +67,3 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_cu AND id IS NOT NULL PRIMARY KEY (tenant_id, customer_id, search_text, id, entity_id) WITH CLUSTERING ORDER BY (customer_id DESC, search_text ASC, id DESC); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer_and_entity AS - SELECT * - from thingsboard.entity_views - WHERE tenant_id IS NOT NULL - AND customer_id IS NOT NULL - AND entity_id IS NOT NULL - AND search_text IS NOT NULL - AND id IS NOT NULL - PRIMARY KEY (tenant_id, customer_id, entity_id, search_text, id) - WITH CLUSTERING ORDER BY (customer_id DESC, entity_id ASC, search_text ASC, id DESC); diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index 347b05409e..5b2dab6bee 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -93,8 +93,6 @@ public class ThingsboardInstallService { databaseUpgradeService.upgradeDatabase("2.0.0"); - dataUpdateService.updateData("2.0.0"); - log.info("Updating system data..."); systemDataLoaderService.deleteSystemWidgetBundle("charts"); diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultDataUpdateService.java index 0194a5dfd7..5daebcc3c5 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultDataUpdateService.java @@ -49,10 +49,6 @@ public class DefaultDataUpdateService implements DataUpdateService { log.info("Updating data from version 1.4.0 to 2.0.0 ..."); tenantsDefaultRuleChainUpdater.updateEntities(null); break; - case "2.0.0": - log.info("Updating data from version 2.0.0 to 2.1.1 ..."); - tenantsDefaultRuleChainUpdater.updateEntities(null); - break; default: throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion); } 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 7f4f23a0ef..eaf1018ff2 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 @@ -30,7 +30,15 @@ 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.*; +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.EntityViewId; +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.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.controller.HttpValidationCallback; diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index 5c62e6ad13..98ca7c244a 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -22,7 +22,11 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import org.thingsboard.server.common.data.*; +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.User; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.objects.AttributesEntityView; import org.thingsboard.server.common.data.objects.TelemetryEntityView; @@ -31,7 +35,10 @@ import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.dao.model.ModelConstants; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -43,7 +50,6 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes private Tenant savedTenant; private User tenantAdmin; private Device testDevice; - private TelemetryEntityView obj; @Before public void beforeTest() throws Exception { @@ -67,14 +73,6 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes device.setName("Test device"); device.setType("default"); testDevice = doPost("/api/device", device, Device.class); - obj = new TelemetryEntityView( - Arrays.asList("109L", "209L"), - new AttributesEntityView( - Arrays.asList("caKey1", "caKey2"), - Arrays.asList("saKey1", "saKey2", "saKey3"), - Arrays.asList("shKey1", "shKey2", "shKey3", "shKey4") - ) - ); } @After @@ -239,14 +237,16 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes doDelete("/api/customer/entityView/" + view.getId().getId().toString()).andExpect(status().isOk()); } TextPageData pageData = doGetTypedWithPageLink(urlTemplate, - new TypeReference>(){}, new TextPageLink(4, name1)); + new TypeReference>() { + }, new TextPageLink(4, name1)); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); for (EntityView view : loadedNamesOfView2) { doDelete("/api/customer/entityView/" + view.getId().getId().toString()).andExpect(status().isOk()); } - pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference>(){}, + pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference>() { + }, new TextPageLink(4, name2)); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); @@ -287,14 +287,16 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes doDelete("/api/entityView/" + view.getId().getId().toString()).andExpect(status().isOk()); } TextPageData pageData = doGetTypedWithPageLink("/api/tenant/entityViews?", - new TypeReference>(){}, new TextPageLink(4, name1)); + new TypeReference>() { + }, new TextPageLink(4, name1)); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); for (EntityView view : loadedNamesOfView2) { doDelete("/api/entityView/" + view.getId().getId().toString()).andExpect(status().isOk()); } - pageData = doGetTypedWithPageLink("/api/tenant/entityViews?", new TypeReference>(){}, + pageData = doGetTypedWithPageLink("/api/tenant/entityViews?", new TypeReference>() { + }, new TextPageLink(4, name2)); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); @@ -305,7 +307,14 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes view.setEntityId(testDevice.getId()); view.setTenantId(savedTenant.getId()); view.setName(name); - view.setKeys(new TelemetryEntityView(obj)); + + view.setKeys(new TelemetryEntityView( + Arrays.asList("109L", "209L"), + new AttributesEntityView( + Arrays.asList("caKey1", "caKey2"), + Arrays.asList("saKey1", "saKey2", "saKey3"), + Arrays.asList("shKey1", "shKey2", "shKey3", "shKey4")))); + return doPost("/api/entityView", view, EntityView.class); } @@ -346,7 +355,8 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes List loadedItems = new ArrayList<>(); TextPageData pageData; do { - pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference>(){}, pageLink); + pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference>() { + }, pageLink); loadedItems.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageData.getNextPageLink(); 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 b86c605464..25b066d2ef 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 @@ -15,7 +15,9 @@ */ package org.thingsboard.server.common.data; -import lombok.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityViewId; diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java index 36b250d218..9d96f3a97a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java @@ -32,6 +32,7 @@ import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.entity.AbstractEntityService; +import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.service.DataValidator; @@ -69,6 +70,9 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom @Autowired private DeviceService deviceService; + @Autowired + private EntityViewService entityViewService; + @Autowired private DashboardService dashboardService; @@ -113,6 +117,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom dashboardService.unassignCustomerDashboards(customerId); assetService.unassignCustomerAssets(customer.getTenantId(), customerId); deviceService.unassignCustomerDevices(customer.getTenantId(), customerId); + entityViewService.unassignCustomerEntityViews(customer.getTenantId(), customerId); userService.deleteCustomerUsers(customer.getTenantId(), customerId); deleteEntityRelations(customerId); customerDao.removeById(customerId.getId()); 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 98f6105646..e866bc89b8 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 @@ -30,11 +30,23 @@ 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 java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.UUID; import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; import static com.datastax.driver.core.querybuilder.QueryBuilder.select; -import static org.thingsboard.server.dao.model.ModelConstants.*; +import static org.thingsboard.server.dao.model.ModelConstants.CUSTOMER_ID_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_ID_COLUMN; +import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_SEARCH_TEXT; +import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_BY_TENANT_AND_NAME; +import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME; +import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_NAME_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_TABLE_FAMILY_NAME; +import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_TENANT_ID_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.TENANT_ID_PROPERTY; /** * Created by Victor Basanets on 9/06/2017. @@ -84,19 +96,6 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao findEntityViewByTenantIdAndEntityId(UUID tenantId, UUID entityId, TextPageLink pageLink) { - log.debug("Try to find entity views by tenantId [{}], entityId [{}] and pageLink [{}]", - tenantId, entityId, pageLink); - List entityViewEntities = findPageWithTextSearch( - ENTITY_VIEW_BY_TENANT_AND_ENTITY_AND_SEARCH_TEXT, - Arrays.asList(eq(CUSTOMER_ID_PROPERTY, entityId), eq(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 findEntityViewsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) { log.debug("Try to find entity views by tenantId [{}], customerId[{}] and pageLink [{}]", @@ -110,26 +109,6 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao findEntityViewsByTenantIdAndCustomerIdAndEntityId(UUID tenantId, - UUID customerId, - UUID entityId, - TextPageLink pageLink) { - - log.debug("Try to find entity views by tenantId [{}], customerId [{}], entityId [{}] and pageLink [{}]", - tenantId, customerId, entityId, pageLink); - List entityViewEntities = findPageWithTextSearch( - ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_ENTITY_AND_SEARCH_TEXT, - Arrays.asList( - eq(TENANT_ID_PROPERTY, tenantId), - eq(CUSTOMER_ID_PROPERTY, customerId), - eq(ENTITY_ID_COLUMN, entityId)), - pageLink); - log.trace("Found devices [{}] by tenantId [{}], customerId [{}], entityId [{}] and pageLink [{}]", - entityViewEntities, tenantId, customerId, entityId, pageLink); - return DaoUtil.convertDataList(entityViewEntities); - } - @Override public ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(UUID tenantId, UUID entityId) { log.debug("Try to find entity views by tenantId [{}] and entityId [{}]", tenantId, entityId); 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 be643ef363..742cb92d90 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 @@ -56,18 +56,6 @@ public interface EntityViewDao extends Dao { */ Optional findEntityViewByTenantIdAndName(UUID tenantId, String name); - /** - * Find entity views by tenantId, entityId and page link. - * - * @param tenantId the tenantId - * @param entityId the entityId - * @param pageLink the page link - * @return the list of entity view objects - */ - List findEntityViewByTenantIdAndEntityId(UUID tenantId, - UUID entityId, - TextPageLink pageLink); - /** * Find entity views by tenantId, customerId and page link. * @@ -80,19 +68,6 @@ public interface EntityViewDao extends Dao { UUID customerId, TextPageLink pageLink); - /** - * Find entity views by tenantId, customerId, entityId and page link. - * - * @param tenantId the tenantId - * @param customerId the customerId - * @param entityId the entityId - * @param pageLink the page link - * @return the list of entity view objects - */ - List findEntityViewsByTenantIdAndCustomerIdAndEntityId(UUID tenantId, - UUID customerId, - UUID entityId, - TextPageLink pageLink); ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(UUID tenantId, UUID entityId); } 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 b9c238a79a..89b7e2f85c 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 @@ -16,14 +16,12 @@ package org.thingsboard.server.dao.entityview; import com.google.common.util.concurrent.ListenableFuture; -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.device.DeviceSearchQuery; import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; -import org.thingsboard.server.common.data.id.*; +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.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; @@ -36,8 +34,6 @@ public interface EntityViewService { EntityView findEntityViewById(EntityViewId entityViewId); - EntityView findEntityViewByTenantIdAndName(TenantId tenantId, String name); - EntityView saveEntityView(EntityView entityView); EntityView assignEntityViewToCustomer(EntityViewId entityViewId, CustomerId customerId); @@ -48,19 +44,11 @@ public interface EntityViewService { TextPageData findEntityViewByTenantId(TenantId tenantId, TextPageLink pageLink); - TextPageData findEntityViewByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, - TextPageLink pageLink); - - void deleteEntityViewByTenantId(TenantId tenantId); + void deleteEntityViewsByTenantId(TenantId tenantId); TextPageData findEntityViewsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink); - TextPageData findEntityViewsByTenantIdAndCustomerIdAndEntityId(TenantId tenantId, - CustomerId customerId, - EntityId entityId, - TextPageLink pageLink); - void unassignCustomerEntityViews(TenantId tenantId, CustomerId customerId); ListenableFuture 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 c13261c003..dd3e61d611 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 @@ -96,15 +96,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti return entityViewDao.findById(entityViewId.getId()); } - @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #name}") - @Override - public EntityView findEntityViewByTenantIdAndName(TenantId tenantId, String name) { - log.trace("Executing findEntityViewByTenantIdAndName [{}][{}]", tenantId, name); - validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - return entityViewDao.findEntityViewByTenantIdAndName(tenantId.getId(), name) - .orElse(null); - } - @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityView.tenantId, #entityView.name}") @Override public EntityView saveEntityView(EntityView entityView) { @@ -187,24 +178,8 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti } @Override - public TextPageData findEntityViewByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, - TextPageLink pageLink) { - - log.trace("Executing findEntityViewByTenantIdAndType, tenantId [{}], entityId [{}], pageLink [{}]", - tenantId, entityId, pageLink); - - validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - validateString(entityId.toString(), "Incorrect entityId " + entityId.toString()); - validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); - List entityViews = entityViewDao.findEntityViewByTenantIdAndEntityId(tenantId.getId(), - entityId.getId(), pageLink); - - return new TextPageData<>(entityViews, pageLink); - } - - @Override - public void deleteEntityViewByTenantId(TenantId tenantId) { - log.trace("Executing deleteEntityViewByTenantId, tenantId [{}]", tenantId); + public void deleteEntityViewsByTenantId(TenantId tenantId) { + log.trace("Executing deleteEntityViewsByTenantId, tenantId [{}]", tenantId); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); tenantEntityViewRemover.removeEntities(tenantId); } @@ -225,25 +200,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti return new TextPageData<>(entityViews, pageLink); } - @Override - public TextPageData findEntityViewsByTenantIdAndCustomerIdAndEntityId(TenantId tenantId, - CustomerId customerId, - EntityId entityId, - TextPageLink pageLink) { - - log.trace("Executing findEntityViewsByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}]," + - " entityId [{}], pageLink [{}]", tenantId, customerId, entityId, pageLink); - - validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); - validateString(entityId.toString(), "Incorrect entityId " + entityId.toString()); - validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); - List entityViews = entityViewDao.findEntityViewsByTenantIdAndCustomerIdAndEntityId( - tenantId.getId(), customerId.getId(), entityId.getId(), pageLink); - - return new TextPageData<>(entityViews, pageLink); - } - @Override public void unassignCustomerEntityViews(TenantId tenantId, CustomerId customerId) { log.trace("Executing unassignCustomerEntityViews, tenantId [{}], customerId [{}]", tenantId, customerId); 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 45d0ff9493..9890ff62d3 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 @@ -150,15 +150,13 @@ 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_BY_TENANT_AND_CUSTOMER_AND_ENTITY_AND_SEARCH_TEXT = "entity_views_by_tenant_and_customer_and_entity"; - public static final String ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_SEARCH_TEXT = "entity_views_by_tenant_and_customer"; + public static final String ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_SEARCH_TEXT = "entity_view_by_tenant_and_customer"; public static final String ENTITY_VIEW_KEYS_PROPERTY = "keys"; public static final String ENTITY_VIEW_START_TS_PROPERTY = "start_ts"; public static final String ENTITY_VIEW_END_TS_PROPERTY = "end_ts"; 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"; - public static final String ENTITY_VIEW_BY_TENANT_AND_NAME = "entity_views_by_tenant_and_name"; - public static final String ENTITY_VIEW_BY_TENANT_AND_ENTITY_AND_SEARCH_TEXT = "entity_view_by_tenant_and_entity"; + public static final String ENTITY_VIEW_BY_TENANT_AND_NAME = "entity_view_by_tenant_and_name"; /** * 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 79dd497173..eb7f4fe65e 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 @@ -24,10 +24,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; +import lombok.extern.slf4j.Slf4j; 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.*; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EntityIdFactory; +import org.thingsboard.server.common.data.id.EntityViewId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.objects.TelemetryEntityView; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.SearchTextEntity; @@ -48,6 +52,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY; @Table(name = ENTITY_VIEW_TABLE_FAMILY_NAME) @EqualsAndHashCode @ToString +@Slf4j public class EntityViewEntity implements SearchTextEntity { @PartitionKey(value = 0) @@ -112,7 +117,7 @@ public class EntityViewEntity implements SearchTextEntity { try { this.keys = mapper.writeValueAsString(entityView.getKeys()); } catch (IOException e) { - e.printStackTrace(); + log.error("Unable to serialize entity view keys!", e); } this.startTs = entityView.getStartTimeMs(); this.endTs = entityView.getEndTimeMs(); @@ -142,7 +147,7 @@ public class EntityViewEntity implements SearchTextEntity { try { entityView.setKeys(mapper.readValue(keys, TelemetryEntityView.class)); } catch (IOException e) { - e.printStackTrace(); + log.error("Unable to read entity view keys!", e); } entityView.setStartTimeMs(startTs); entityView.setEndTimeMs(endTs); 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 96d187cfb6..60f6951b80 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 @@ -20,18 +20,26 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.extern.slf4j.Slf4j; import org.hibernate.annotations.Type; 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.*; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EntityIdFactory; +import org.thingsboard.server.common.data.id.EntityViewId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.objects.TelemetryEntityView; import org.thingsboard.server.dao.model.BaseSqlEntity; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.SearchTextEntity; import org.thingsboard.server.dao.util.mapping.JsonStringType; -import javax.persistence.*; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.Table; import java.io.IOException; import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_TYPE_PROPERTY; @@ -45,6 +53,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_TYPE_PROPER @Entity @TypeDef(name = "json", typeClass = JsonStringType.class) @Table(name = ModelConstants.ENTITY_VIEW_TABLE_FAMILY_NAME) +@Slf4j public class EntityViewEntity extends BaseSqlEntity implements SearchTextEntity { @Column(name = ModelConstants.ENTITY_VIEW_ENTITY_ID_PROPERTY) @@ -103,7 +112,7 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc try { this.keys = mapper.writeValueAsString(entityView.getKeys()); } catch (IOException e) { - e.printStackTrace(); + log.error("Unable to serialize entity view keys!", e); } this.startTs = entityView.getStartTimeMs(); this.endTs = entityView.getEndTimeMs(); @@ -139,7 +148,7 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc try { entityView.setKeys(mapper.readValue(keys, TelemetryEntityView.class)); } catch (IOException e) { - e.printStackTrace(); + log.error("Unable to read entity view keys!", e); } entityView.setStartTimeMs(startTs); entityView.setEndTimeMs(endTs); 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 f1ee3fd272..0f5fdf5fba 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 @@ -40,16 +40,6 @@ public interface EntityViewRepository extends CrudRepository :idOffset ORDER BY e.id") - List findByTenantIdAndEntityId(@Param("tenantId") String tenantId, - @Param("entityId") String entityId, - @Param("textSearch") String textSearch, - @Param("idOffset") String idOffset, - Pageable pageable); - @Query("SELECT e FROM EntityViewEntity e WHERE e.tenantId = :tenantId " + "AND e.customerId = :customerId " + "AND LOWER(e.searchText) LIKE LOWER(CONCAT(:searchText, '%')) " + @@ -60,25 +50,7 @@ public interface EntityViewRepository extends CrudRepository :idOffset ORDER BY e.id") - List findByTenantIdAndCustomerIdAndEntityId(@Param("tenantId") String tenantId, - @Param("customerId") String customerId, - @Param("entityId") String entityId, - @Param("textSearch") String textSearch, - @Param("idOffset") String idOffset, - Pageable pageable); - EntityViewEntity findByTenantIdAndName(String tenantId, String name); - List findAllByTenantIdAndCustomerIdAndIdIn(String tenantId, - String customerId, - List entityViewsIds); - - List findAllByTenantIdAndIdIn(String tenantId, List entityViewsIds); - List findAllByTenantIdAndEntityId(String tenantId, String entityId); } 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 4ff21ab892..0cd1b2b0d6 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 @@ -53,7 +53,7 @@ public class JpaEntityViewDao extends JpaAbstractSearchTextDao getEntityClass() { @@ -81,19 +81,6 @@ public class JpaEntityViewDao extends JpaAbstractSearchTextDao findEntityViewByTenantIdAndEntityId(UUID tenantId, - UUID entityId, - TextPageLink pageLink) { - return DaoUtil.convertDataList( - entityViewRepository.findByTenantIdAndEntityId( - fromTimeUUID(tenantId), - fromTimeUUID(entityId), - Objects.toString(pageLink.getTextSearch(), ""), - pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), - new PageRequest(0, pageLink.getLimit()))); - } - @Override public List findEntityViewsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, @@ -108,22 +95,6 @@ public class JpaEntityViewDao extends JpaAbstractSearchTextDao findEntityViewsByTenantIdAndCustomerIdAndEntityId(UUID tenantId, - UUID customerId, - UUID entityId, - TextPageLink pageLink) { - return DaoUtil.convertDataList( - entityViewRepository.findByTenantIdAndCustomerIdAndEntityId( - fromTimeUUID(tenantId), - fromTimeUUID(customerId), - fromTimeUUID(entityId), - Objects.toString(pageLink.getTextSearch(), ""), - pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), - new PageRequest(0, pageLink.getLimit()) - )); - } - @Override public ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(UUID tenantId, UUID entityId) { return service.submit(() -> DaoUtil.convertDataList( diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index d92c9410e5..a94e715616 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -29,6 +29,7 @@ import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.entity.AbstractEntityService; +import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.service.DataValidator; @@ -63,6 +64,9 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @Autowired private DeviceService deviceService; + @Autowired + private EntityViewService entityViewService; + @Autowired private WidgetsBundleService widgetsBundleService; @@ -103,6 +107,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe dashboardService.deleteDashboardsByTenantId(tenantId); assetService.deleteAssetsByTenantId(tenantId); deviceService.deleteDevicesByTenantId(tenantId); + entityViewService.deleteEntityViewsByTenantId(tenantId); userService.deleteTenantAdmins(tenantId); ruleChainService.deleteRuleChainsByTenantId(tenantId); tenantDao.removeById(tenantId.getId()); diff --git a/dao/src/main/resources/cassandra/schema.cql b/dao/src/main/resources/cassandra/schema.cql index 4645420eb8..07cecd0453 100644 --- a/dao/src/main/resources/cassandra/schema.cql +++ b/dao/src/main/resources/cassandra/schema.cql @@ -674,7 +674,7 @@ CREATE TABLE IF NOT EXISTS thingsboard.entity_views ( PRIMARY KEY (id, entity_id, tenant_id, customer_id) ); -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_name AS +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_name AS SELECT * from thingsboard.entity_views WHERE tenant_id IS NOT NULL @@ -696,18 +696,7 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_sea PRIMARY KEY (tenant_id, search_text, id, customer_id, entity_id) WITH CLUSTERING ORDER BY (search_text ASC, id DESC, customer_id DESC); -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_entity AS - SELECT * - from thingsboard.entity_views - WHERE tenant_id IS NOT NULL - AND customer_id IS NOT NULL - AND entity_id IS NOT NULL - AND search_text IS NOT NULL - AND id IS NOT NULL - PRIMARY KEY (tenant_id, entity_id, search_text, id, customer_id) - WITH CLUSTERING ORDER BY (entity_id ASC, search_text ASC, id DESC, customer_id DESC); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer AS +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_customer AS SELECT * from thingsboard.entity_views WHERE tenant_id IS NOT NULL @@ -717,14 +706,3 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_cu AND id IS NOT NULL PRIMARY KEY (tenant_id, customer_id, search_text, id, entity_id) WITH CLUSTERING ORDER BY (customer_id DESC, search_text ASC, id DESC); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer_and_entity AS - SELECT * - from thingsboard.entity_views - WHERE tenant_id IS NOT NULL - AND customer_id IS NOT NULL - AND entity_id IS NOT NULL - AND search_text IS NOT NULL - AND id IS NOT NULL - PRIMARY KEY (tenant_id, customer_id, entity_id, search_text, id) - WITH CLUSTERING ORDER BY (customer_id DESC, entity_id ASC, search_text ASC, id DESC); diff --git a/dao/src/test/resources/sql/drop-all-tables.sql b/dao/src/test/resources/sql/drop-all-tables.sql index ebc04b3938..b1fb72cc07 100644 --- a/dao/src/test/resources/sql/drop-all-tables.sql +++ b/dao/src/test/resources/sql/drop-all-tables.sql @@ -19,4 +19,4 @@ DROP TABLE IF EXISTS widget_type; DROP TABLE IF EXISTS widgets_bundle; DROP TABLE IF EXISTS rule_node; DROP TABLE IF EXISTS rule_chain; -DROP TABLE IF EXISTS entity_views; \ No newline at end of file +DROP TABLE IF EXISTS entity_views; From 8d7a27c49c9c2a9412489bfab3ae2fb3c2a2297c Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 19 Sep 2018 10:44:29 +0300 Subject: [PATCH 097/118] Added check for keys --- .../controller/BaseEntityViewControllerTest.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index 98ca7c244a..b368ea1989 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -50,6 +50,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes private Tenant savedTenant; private User tenantAdmin; private Device testDevice; + private TelemetryEntityView keys; @Before public void beforeTest() throws Exception { @@ -73,6 +74,13 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes device.setName("Test device"); device.setType("default"); testDevice = doPost("/api/device", device, Device.class); + + keys = new TelemetryEntityView( + Arrays.asList("109L", "209L"), + new AttributesEntityView( + Arrays.asList("caKey1", "caKey2"), + Arrays.asList("saKey1", "saKey2", "saKey3"), + Arrays.asList("shKey1", "shKey2", "shKey3", "shKey4"))); } @After @@ -108,6 +116,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes EntityView foundEntityView = doGet("/api/entityView/" + savedView.getId().getId().toString(), EntityView.class); Assert.assertEquals(foundEntityView.getName(), savedView.getName()); + Assert.assertEquals(foundEntityView.getKeys(), keys); } @Test @@ -308,12 +317,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes view.setTenantId(savedTenant.getId()); view.setName(name); - view.setKeys(new TelemetryEntityView( - Arrays.asList("109L", "209L"), - new AttributesEntityView( - Arrays.asList("caKey1", "caKey2"), - Arrays.asList("saKey1", "saKey2", "saKey3"), - Arrays.asList("shKey1", "shKey2", "shKey3", "shKey4")))); + view.setKeys(keys); return doPost("/api/entityView", view, EntityView.class); } From 2adb39ba6c11733ffd763e59e04ed28e6fd434f3 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Thu, 20 Sep 2018 16:03:44 +0300 Subject: [PATCH 098/118] code review fixes --- .../src/main/resources/thingsboard.yml | 6 +- .../controller/ControllerNoSqlTestSuite.java | 3 +- .../controller/ControllerSqlTestSuite.java | 2 +- .../server/mqtt/MqttNoSqlTestSuite.java | 3 +- .../server/mqtt/MqttSqlTestSuite.java | 4 +- .../rules/RuleEngineNoSqlTestSuite.java | 3 +- .../server/rules/RuleEngineSqlTestSuite.java | 2 +- .../server/system/SystemNoSqlTestSuite.java | 3 +- .../server/system/SystemSqlTestSuite.java | 2 +- .../server/dao/util/HybridDao.java | 22 - .../server/dao/util/NoSqlAnyDao.java | 2 +- .../thingsboard/server/dao/util/NoSqlDao.java | 2 +- .../thingsboard/server/dao/util/SqlDao.java | 2 +- dao/src/main/resources/cassandra/schema.cql | 640 ------------------ dao/src/main/resources/sql/schema.sql | 253 ------- .../server/dao/JpaDaoTestSuite.java | 2 +- .../server/dao/NoSqlDaoServiceTestSuite.java | 4 +- .../server/dao/SqlDaoServiceTestSuite.java | 2 +- dao/src/test/resources/nosql-test.properties | 3 +- dao/src/test/resources/sql-test.properties | 3 +- docker/k8s/cassandra-setup.yaml | 4 +- docker/k8s/cassandra-upgrade.yaml | 4 +- docker/k8s/tb.yaml | 7 +- docker/tb.env | 3 +- docker/tb/run-application.sh | 4 +- 25 files changed, 42 insertions(+), 943 deletions(-) delete mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/HybridDao.java delete mode 100644 dao/src/main/resources/cassandra/schema.cql delete mode 100644 dao/src/main/resources/sql/schema.sql diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index a379e472aa..0cc075c1fc 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -151,7 +151,6 @@ quota: # Enable Host API Limits enabled: "${QUOTA_TENANT_ENABLED:false}" # Array of whitelist tenants - # Array of whitelist tenants whitelist: "${QUOTA_TENANT_WHITELIST:}" # Array of blacklist tenants blacklist: "${QUOTA_HOST_BLACKLIST:}" @@ -160,11 +159,10 @@ quota: intervalMin: 2 database: - type: "${DATABASE_TYPE:sql}" # cassandra OR sql entities: - type: "${DATABASE_TYPE:sql}" # cassandra OR sql + type: "${DATABASE_TS_TYPE:sql}" # cassandra OR sql ts: - type: "${DATABASE_TYPE:sql}" # cassandra OR sql (for hybrid mode, only this value should be cassandra) + type: "${DATABASE_CASSANDRA_TYPE:sql}" # cassandra OR sql (for hybrid mode, only this value should be cassandra) # Cassandra driver configuration parameters diff --git a/application/src/test/java/org/thingsboard/server/controller/ControllerNoSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/controller/ControllerNoSqlTestSuite.java index 2e8848305f..f378437312 100644 --- a/application/src/test/java/org/thingsboard/server/controller/ControllerNoSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/controller/ControllerNoSqlTestSuite.java @@ -32,7 +32,8 @@ public class ControllerNoSqlTestSuite { public static CustomCassandraCQLUnit cassandraUnit = new CustomCassandraCQLUnit( Arrays.asList( - new ClassPathCQLDataSet("cassandra/schema.cql", false, false), + new ClassPathCQLDataSet("cassandra/schema-ts.cql", false, false), + new ClassPathCQLDataSet("cassandra/schema-entities.cql", false, false), new ClassPathCQLDataSet("cassandra/system-data.cql", false, false), new ClassPathCQLDataSet("cassandra/system-test.cql", false, false)), "cassandra-test.yaml", 30000l); 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 f316051212..3b3d9b04a6 100644 --- a/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java @@ -30,7 +30,7 @@ public class ControllerSqlTestSuite { @ClassRule public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema.sql", "sql/system-data.sql"), + Arrays.asList("sql/schema-ts.sql", "sql/schema-entities.sql", "sql/system-data.sql"), "sql/drop-all-tables.sql", "sql-test.properties"); } diff --git a/application/src/test/java/org/thingsboard/server/mqtt/MqttNoSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/mqtt/MqttNoSqlTestSuite.java index c4a969b1a9..2bb8a81ef2 100644 --- a/application/src/test/java/org/thingsboard/server/mqtt/MqttNoSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/mqtt/MqttNoSqlTestSuite.java @@ -32,7 +32,8 @@ public class MqttNoSqlTestSuite { public static CustomCassandraCQLUnit cassandraUnit = new CustomCassandraCQLUnit( Arrays.asList( - new ClassPathCQLDataSet("cassandra/schema.cql", false, false), + new ClassPathCQLDataSet("cassandra/schema-ts.cql", false, false), + new ClassPathCQLDataSet("cassandra/schema-entities.cql", false, false), new ClassPathCQLDataSet("cassandra/system-data.cql", false, false)), "cassandra-test.yaml", 30000l); } diff --git a/application/src/test/java/org/thingsboard/server/mqtt/MqttSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/mqtt/MqttSqlTestSuite.java index 5ddbb67c97..1389c7edde 100644 --- a/application/src/test/java/org/thingsboard/server/mqtt/MqttSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/mqtt/MqttSqlTestSuite.java @@ -15,11 +15,9 @@ */ package org.thingsboard.server.mqtt; -import org.cassandraunit.dataset.cql.ClassPathCQLDataSet; import org.junit.ClassRule; import org.junit.extensions.cpsuite.ClasspathSuite; import org.junit.runner.RunWith; -import org.thingsboard.server.dao.CustomCassandraCQLUnit; import org.thingsboard.server.dao.CustomSqlUnit; import java.util.Arrays; @@ -31,7 +29,7 @@ public class MqttSqlTestSuite { @ClassRule public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema.sql", "sql/system-data.sql"), + Arrays.asList("sql/schema-ts.sql", "sql/schema-entities.sql", "sql/system-data.sql"), "sql/drop-all-tables.sql", "sql-test.properties"); } diff --git a/application/src/test/java/org/thingsboard/server/rules/RuleEngineNoSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/rules/RuleEngineNoSqlTestSuite.java index bffe4913ef..c1d1e6cbaf 100644 --- a/application/src/test/java/org/thingsboard/server/rules/RuleEngineNoSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/rules/RuleEngineNoSqlTestSuite.java @@ -35,7 +35,8 @@ public class RuleEngineNoSqlTestSuite { public static CustomCassandraCQLUnit cassandraUnit = new CustomCassandraCQLUnit( Arrays.asList( - new ClassPathCQLDataSet("cassandra/schema.cql", false, false), + new ClassPathCQLDataSet("cassandra/schema-ts.cql", false, false), + new ClassPathCQLDataSet("cassandra/schema-entities.cql", false, false), new ClassPathCQLDataSet("cassandra/system-data.cql", false, false)), "cassandra-test.yaml", 30000l); diff --git a/application/src/test/java/org/thingsboard/server/rules/RuleEngineSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/rules/RuleEngineSqlTestSuite.java index 7b13e2fd54..e09d820777 100644 --- a/application/src/test/java/org/thingsboard/server/rules/RuleEngineSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/rules/RuleEngineSqlTestSuite.java @@ -30,7 +30,7 @@ public class RuleEngineSqlTestSuite { @ClassRule public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema.sql", "sql/system-data.sql"), + Arrays.asList("sql/schema-ts.sql", "sql/schema-entities.sql", "sql/system-data.sql"), "sql/drop-all-tables.sql", "sql-test.properties"); } diff --git a/application/src/test/java/org/thingsboard/server/system/SystemNoSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/system/SystemNoSqlTestSuite.java index 70e3fe2147..ebde304fd6 100644 --- a/application/src/test/java/org/thingsboard/server/system/SystemNoSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/system/SystemNoSqlTestSuite.java @@ -34,7 +34,8 @@ public class SystemNoSqlTestSuite { public static CustomCassandraCQLUnit cassandraUnit = new CustomCassandraCQLUnit( Arrays.asList( - new ClassPathCQLDataSet("cassandra/schema.cql", false, false), + new ClassPathCQLDataSet("cassandra/schema-ts.cql", false, false), + new ClassPathCQLDataSet("cassandra/schema-entities.cql", false, false), new ClassPathCQLDataSet("cassandra/system-data.cql", false, false)), "cassandra-test.yaml", 30000l); } diff --git a/application/src/test/java/org/thingsboard/server/system/SystemSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/system/SystemSqlTestSuite.java index 97c67491f1..8ca6dcc877 100644 --- a/application/src/test/java/org/thingsboard/server/system/SystemSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/system/SystemSqlTestSuite.java @@ -31,7 +31,7 @@ public class SystemSqlTestSuite { @ClassRule public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema.sql", "sql/system-data.sql"), + Arrays.asList("sql/schema-ts.sql", "sql/schema-entities.sql", "sql/system-data.sql"), "sql/drop-all-tables.sql", "sql-test.properties"); diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/HybridDao.java b/dao/src/main/java/org/thingsboard/server/dao/util/HybridDao.java deleted file mode 100644 index 2caf8ccace..0000000000 --- a/dao/src/main/java/org/thingsboard/server/dao/util/HybridDao.java +++ /dev/null @@ -1,22 +0,0 @@ -/** - * 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.util; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; - -@ConditionalOnExpression("'${database.entity.type}'=='sql' && '${database.ts.type}'=='cassandra'") -public @interface HybridDao { -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/NoSqlAnyDao.java b/dao/src/main/java/org/thingsboard/server/dao/util/NoSqlAnyDao.java index 7e7aefa3c3..a8049eec5f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/NoSqlAnyDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/NoSqlAnyDao.java @@ -17,6 +17,6 @@ package org.thingsboard.server.dao.util; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -@ConditionalOnExpression("'${database.type}'=='cassandra' || '${database.ts.type}'=='cassandra'") +@ConditionalOnExpression("'${database.ts.type}'=='cassandra' || '${database.entities.type}'=='cassandra'") public @interface NoSqlAnyDao { } diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/NoSqlDao.java b/dao/src/main/java/org/thingsboard/server/dao/util/NoSqlDao.java index 96dbdab758..c3a719d893 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/NoSqlDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/NoSqlDao.java @@ -17,6 +17,6 @@ package org.thingsboard.server.dao.util; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -@ConditionalOnProperty(prefix = "database", value = "type", havingValue = "cassandra") +@ConditionalOnProperty(prefix = "database.entities", value = "type", havingValue = "cassandra") public @interface NoSqlDao { } diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/SqlDao.java b/dao/src/main/java/org/thingsboard/server/dao/util/SqlDao.java index 3986f022d9..ab39c847b6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/SqlDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/SqlDao.java @@ -17,6 +17,6 @@ package org.thingsboard.server.dao.util; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -@ConditionalOnProperty(prefix = "database", value = "type", havingValue = "sql") +@ConditionalOnProperty(prefix = "database.entities", value = "type", havingValue = "sql") public @interface SqlDao { } diff --git a/dao/src/main/resources/cassandra/schema.cql b/dao/src/main/resources/cassandra/schema.cql deleted file mode 100644 index f03122ab6b..0000000000 --- a/dao/src/main/resources/cassandra/schema.cql +++ /dev/null @@ -1,640 +0,0 @@ --- --- 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. --- - -CREATE KEYSPACE IF NOT EXISTS thingsboard -WITH replication = { - 'class' : 'SimpleStrategy', - 'replication_factor' : 1 -}; - -CREATE TABLE IF NOT EXISTS thingsboard.user ( - id timeuuid, - tenant_id timeuuid, - customer_id timeuuid, - email text, - search_text text, - authority text, - first_name text, - last_name text, - additional_info text, - PRIMARY KEY (id, tenant_id, customer_id, authority) -); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.user_by_email AS - SELECT * - from thingsboard.user - WHERE email IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND id IS NOT NULL AND authority IS NOT - NULL - PRIMARY KEY ( email, tenant_id, customer_id, id, authority ); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.user_by_tenant_and_search_text AS - SELECT * - from thingsboard.user - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND authority IS NOT NULL AND search_text IS NOT NULL AND id - IS NOT NULL - PRIMARY KEY ( tenant_id, customer_id, authority, search_text, id ) - WITH CLUSTERING ORDER BY ( customer_id DESC, authority DESC, search_text ASC, id DESC ); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.user_by_customer_and_search_text AS - SELECT * - from thingsboard.user - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND authority IS NOT NULL AND search_text IS NOT NULL AND id - IS NOT NULL - PRIMARY KEY ( customer_id, tenant_id, authority, search_text, id ) - WITH CLUSTERING ORDER BY ( tenant_id DESC, authority DESC, search_text ASC, id DESC ); - -CREATE TABLE IF NOT EXISTS thingsboard.user_credentials ( - id timeuuid PRIMARY KEY, - user_id timeuuid, - enabled boolean, - password text, - activate_token text, - reset_token text -); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.user_credentials_by_user AS - SELECT * - from thingsboard.user_credentials - WHERE user_id IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( user_id, id ); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.user_credentials_by_activate_token AS - SELECT * - from thingsboard.user_credentials - WHERE activate_token IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( activate_token, id ); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.user_credentials_by_reset_token AS - SELECT * - from thingsboard.user_credentials - WHERE reset_token IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( reset_token, id ); - -CREATE TABLE IF NOT EXISTS thingsboard.admin_settings ( - id timeuuid PRIMARY KEY, - key text, - json_value text -); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.admin_settings_by_key AS - SELECT * - from thingsboard.admin_settings - WHERE key IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( key, id ) - WITH CLUSTERING ORDER BY ( id DESC ); - -CREATE TABLE IF NOT EXISTS thingsboard.tenant ( - id timeuuid, - title text, - search_text text, - region text, - country text, - state text, - city text, - address text, - address2 text, - zip text, - phone text, - email text, - additional_info text, - PRIMARY KEY (id, region) -); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.tenant_by_region_and_search_text AS - SELECT * - from thingsboard.tenant - WHERE region IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( region, search_text, id ) - WITH CLUSTERING ORDER BY ( search_text ASC, id DESC ); - -CREATE TABLE IF NOT EXISTS thingsboard.customer ( - id timeuuid, - tenant_id timeuuid, - title text, - search_text text, - country text, - state text, - city text, - address text, - address2 text, - zip text, - phone text, - email text, - additional_info text, - PRIMARY KEY (id, tenant_id) -); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.customer_by_tenant_and_title AS - SELECT * - from thingsboard.customer - WHERE tenant_id IS NOT NULL AND title IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( tenant_id, title, id ) - WITH CLUSTERING ORDER BY ( title ASC, id DESC ); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.customer_by_tenant_and_search_text AS - SELECT * - from thingsboard.customer - WHERE tenant_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( tenant_id, search_text, id ) - WITH CLUSTERING ORDER BY ( search_text ASC, id DESC ); - -CREATE TABLE IF NOT EXISTS thingsboard.device ( - id timeuuid, - tenant_id timeuuid, - customer_id timeuuid, - name text, - type text, - search_text text, - additional_info text, - PRIMARY KEY (id, tenant_id, customer_id, type) -); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_tenant_and_name AS - SELECT * - from thingsboard.device - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( tenant_id, name, id, customer_id, type) - WITH CLUSTERING ORDER BY ( name ASC, id DESC, customer_id DESC); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_tenant_and_search_text AS - SELECT * - from thingsboard.device - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( tenant_id, search_text, id, customer_id, type) - WITH CLUSTERING ORDER BY ( search_text ASC, id DESC, customer_id DESC); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_tenant_by_type_and_search_text AS - SELECT * - from thingsboard.device - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( tenant_id, type, search_text, id, customer_id) - WITH CLUSTERING ORDER BY ( type ASC, search_text ASC, id DESC, customer_id DESC); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_customer_and_search_text AS - SELECT * - from thingsboard.device - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( customer_id, tenant_id, search_text, id, type ) - WITH CLUSTERING ORDER BY ( tenant_id DESC, search_text ASC, id DESC ); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_customer_by_type_and_search_text AS - SELECT * - from thingsboard.device - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( customer_id, tenant_id, type, search_text, id ) - WITH CLUSTERING ORDER BY ( tenant_id DESC, type ASC, search_text ASC, id DESC ); - -CREATE TABLE IF NOT EXISTS thingsboard.device_credentials ( - id timeuuid PRIMARY KEY, - device_id timeuuid, - credentials_type text, - credentials_id text, - credentials_value text -); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_credentials_by_device AS - SELECT * - from thingsboard.device_credentials - WHERE device_id IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( device_id, id ); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_credentials_by_credentials_id AS - SELECT * - from thingsboard.device_credentials - WHERE credentials_id IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( credentials_id, id ); - -CREATE TABLE IF NOT EXISTS thingsboard.asset ( - id timeuuid, - tenant_id timeuuid, - customer_id timeuuid, - name text, - type text, - search_text text, - additional_info text, - PRIMARY KEY (id, tenant_id, customer_id, type) -); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_tenant_and_name AS - SELECT * - from thingsboard.asset - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( tenant_id, name, id, customer_id, type) - WITH CLUSTERING ORDER BY ( name ASC, id DESC, customer_id DESC); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_tenant_and_search_text AS - SELECT * - from thingsboard.asset - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( tenant_id, search_text, id, customer_id, type) - WITH CLUSTERING ORDER BY ( search_text ASC, id DESC, customer_id DESC); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_tenant_by_type_and_search_text AS - SELECT * - from thingsboard.asset - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( tenant_id, type, search_text, id, customer_id) - WITH CLUSTERING ORDER BY ( type ASC, search_text ASC, id DESC, customer_id DESC); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_customer_and_search_text AS - SELECT * - from thingsboard.asset - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( customer_id, tenant_id, search_text, id, type ) - WITH CLUSTERING ORDER BY ( tenant_id DESC, search_text ASC, id DESC ); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_customer_by_type_and_search_text AS - SELECT * - from thingsboard.asset - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( customer_id, tenant_id, type, search_text, id ) - WITH CLUSTERING ORDER BY ( tenant_id DESC, type ASC, search_text ASC, id DESC ); - -CREATE TABLE IF NOT EXISTS thingsboard.entity_subtype ( - tenant_id timeuuid, - entity_type text, // (DEVICE, ASSET) - type text, - PRIMARY KEY (tenant_id, entity_type, type) -); - -CREATE TABLE IF NOT EXISTS thingsboard.alarm ( - id timeuuid, - tenant_id timeuuid, - type text, - originator_id timeuuid, - originator_type text, - severity text, - status text, - start_ts bigint, - end_ts bigint, - ack_ts bigint, - clear_ts bigint, - details text, - propagate boolean, - PRIMARY KEY ((tenant_id, originator_id, originator_type), type, id) -) WITH CLUSTERING ORDER BY ( type ASC, id DESC); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.alarm_by_id AS - SELECT * - from thingsboard.alarm - WHERE tenant_id IS NOT NULL AND originator_id IS NOT NULL AND originator_type IS NOT NULL AND type IS NOT NULL - AND type IS NOT NULL AND id IS NOT NULL - PRIMARY KEY (id, tenant_id, originator_id, originator_type, type) - WITH CLUSTERING ORDER BY ( tenant_id ASC, originator_id ASC, originator_type ASC, type ASC); - -CREATE TABLE IF NOT EXISTS thingsboard.relation ( - from_id timeuuid, - from_type text, - to_id timeuuid, - to_type text, - relation_type_group text, - relation_type text, - additional_info text, - PRIMARY KEY ((from_id, from_type), relation_type_group, relation_type, to_id, to_type) -) WITH CLUSTERING ORDER BY ( relation_type_group ASC, relation_type ASC, to_id ASC, to_type ASC); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.relation_by_type_and_child_type AS - SELECT * - from thingsboard.relation - WHERE from_id IS NOT NULL AND from_type IS NOT NULL AND relation_type_group IS NOT NULL AND relation_type IS NOT NULL AND to_id IS NOT NULL AND to_type IS NOT NULL - PRIMARY KEY ((from_id, from_type), relation_type_group, relation_type, to_type, to_id) - WITH CLUSTERING ORDER BY ( relation_type_group ASC, relation_type ASC, to_type ASC, to_id DESC); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.reverse_relation AS - SELECT * - from thingsboard.relation - WHERE from_id IS NOT NULL AND from_type IS NOT NULL AND relation_type_group IS NOT NULL AND relation_type IS NOT NULL AND to_id IS NOT NULL AND to_type IS NOT NULL - PRIMARY KEY ((to_id, to_type), relation_type_group, relation_type, from_id, from_type) - WITH CLUSTERING ORDER BY ( relation_type_group ASC, relation_type ASC, from_id ASC, from_type ASC); - -CREATE TABLE IF NOT EXISTS thingsboard.widgets_bundle ( - id timeuuid, - tenant_id timeuuid, - alias text, - title text, - search_text text, - image blob, - PRIMARY KEY (id, tenant_id) -); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.widgets_bundle_by_tenant_and_search_text AS - SELECT * - from thingsboard.widgets_bundle - WHERE tenant_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( tenant_id, search_text, id ) - WITH CLUSTERING ORDER BY ( search_text ASC, id DESC ); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.widgets_bundle_by_tenant_and_alias AS - SELECT * - from thingsboard.widgets_bundle - WHERE tenant_id IS NOT NULL AND alias IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( tenant_id, alias, id ) - WITH CLUSTERING ORDER BY ( alias ASC, id DESC ); - -CREATE TABLE IF NOT EXISTS thingsboard.widget_type ( - id timeuuid, - tenant_id timeuuid, - bundle_alias text, - alias text, - name text, - descriptor text, - PRIMARY KEY (id, tenant_id, bundle_alias) -); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.widget_type_by_tenant_and_aliases AS - SELECT * - from thingsboard.widget_type - WHERE tenant_id IS NOT NULL AND bundle_alias IS NOT NULL AND alias IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( tenant_id, bundle_alias, alias, id ) - WITH CLUSTERING ORDER BY ( bundle_alias ASC, alias ASC, id DESC ); - -CREATE TABLE IF NOT EXISTS thingsboard.dashboard ( - id timeuuid, - tenant_id timeuuid, - title text, - search_text text, - assigned_customers text, - configuration text, - PRIMARY KEY (id, tenant_id) -); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.dashboard_by_tenant_and_search_text AS - SELECT * - from thingsboard.dashboard - WHERE tenant_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( tenant_id, search_text, id ) - WITH CLUSTERING ORDER BY ( search_text ASC, id DESC ); - -CREATE TABLE IF NOT EXISTS thingsboard.ts_kv_cf ( - entity_type text, // (DEVICE, CUSTOMER, TENANT) - entity_id timeuuid, - key text, - partition bigint, - ts bigint, - bool_v boolean, - str_v text, - long_v bigint, - dbl_v double, - PRIMARY KEY (( entity_type, entity_id, key, partition ), ts) -); - -CREATE TABLE IF NOT EXISTS thingsboard.ts_kv_partitions_cf ( - entity_type text, // (DEVICE, CUSTOMER, TENANT) - entity_id timeuuid, - key text, - partition bigint, - PRIMARY KEY (( entity_type, entity_id, key ), partition) -) WITH CLUSTERING ORDER BY ( partition ASC ) - AND compaction = { 'class' : 'LeveledCompactionStrategy' }; - -CREATE TABLE IF NOT EXISTS thingsboard.ts_kv_latest_cf ( - entity_type text, // (DEVICE, CUSTOMER, TENANT) - entity_id timeuuid, - key text, - ts bigint, - bool_v boolean, - str_v text, - long_v bigint, - dbl_v double, - PRIMARY KEY (( entity_type, entity_id ), key) -) WITH compaction = { 'class' : 'LeveledCompactionStrategy' }; - - -CREATE TABLE IF NOT EXISTS thingsboard.attributes_kv_cf ( - entity_type text, // (DEVICE, CUSTOMER, TENANT) - entity_id timeuuid, - attribute_type text, // (CLIENT_SIDE, SHARED, SERVER_SIDE) - attribute_key text, - bool_v boolean, - str_v text, - long_v bigint, - dbl_v double, - last_update_ts bigint, - PRIMARY KEY ((entity_type, entity_id, attribute_type), attribute_key) -) WITH compaction = { 'class' : 'LeveledCompactionStrategy' }; - -CREATE TABLE IF NOT EXISTS thingsboard.component_descriptor ( - id timeuuid, - type text, - scope text, - name text, - search_text text, - clazz text, - configuration_descriptor text, - actions text, - PRIMARY KEY (clazz, id, type, scope) -); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.component_desc_by_type_search_text AS - SELECT * - from thingsboard.component_descriptor - WHERE type IS NOT NULL AND scope IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL AND clazz IS NOT NULL - PRIMARY KEY ( type, search_text, id, clazz, scope) - WITH CLUSTERING ORDER BY ( search_text DESC); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.component_desc_by_scope_type_search_text AS - SELECT * - from thingsboard.component_descriptor - WHERE type IS NOT NULL AND scope IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL AND clazz IS NOT NULL - PRIMARY KEY ( (scope, type), search_text, id, clazz) - WITH CLUSTERING ORDER BY ( search_text DESC); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.component_desc_by_id AS - SELECT * - from thingsboard.component_descriptor - WHERE type IS NOT NULL AND scope IS NOT NULL AND id IS NOT NULL AND clazz IS NOT NULL - PRIMARY KEY ( id, clazz, scope, type ) - WITH CLUSTERING ORDER BY ( clazz ASC, scope ASC, type DESC); - -CREATE TABLE IF NOT EXISTS thingsboard.event ( - tenant_id timeuuid, // tenant or system - id timeuuid, - event_type text, - event_uid text, - entity_type text, - entity_id timeuuid, - body text, - PRIMARY KEY ((tenant_id, entity_type, entity_id), event_type, event_uid) -); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.event_by_type_and_id AS - SELECT * - FROM thingsboard.event - WHERE tenant_id IS NOT NULL AND entity_type IS NOT NULL AND entity_id IS NOT NULL AND id IS NOT NULL - AND event_type IS NOT NULL AND event_uid IS NOT NULL - PRIMARY KEY ((tenant_id, entity_type, entity_id), event_type, id, event_uid) - WITH CLUSTERING ORDER BY (event_type ASC, id ASC, event_uid ASC); - - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.event_by_id AS - SELECT * - FROM thingsboard.event - WHERE tenant_id IS NOT NULL AND entity_type IS NOT NULL AND entity_id IS NOT NULL AND id IS NOT NULL - AND event_type IS NOT NULL AND event_uid IS NOT NULL - PRIMARY KEY ((tenant_id, entity_type, entity_id), id, event_type, event_uid) - WITH CLUSTERING ORDER BY (id ASC, event_type ASC, event_uid ASC); - -CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_entity_id ( - tenant_id timeuuid, - id timeuuid, - customer_id timeuuid, - entity_id timeuuid, - entity_type text, - entity_name text, - user_id timeuuid, - user_name text, - action_type text, - action_data text, - action_status text, - action_failure_details text, - PRIMARY KEY ((tenant_id, entity_id, entity_type), id) -); - -CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_customer_id ( - tenant_id timeuuid, - id timeuuid, - customer_id timeuuid, - entity_id timeuuid, - entity_type text, - entity_name text, - user_id timeuuid, - user_name text, - action_type text, - action_data text, - action_status text, - action_failure_details text, - PRIMARY KEY ((tenant_id, customer_id), id) -); - -CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_user_id ( - tenant_id timeuuid, - id timeuuid, - customer_id timeuuid, - entity_id timeuuid, - entity_type text, - entity_name text, - user_id timeuuid, - user_name text, - action_type text, - action_data text, - action_status text, - action_failure_details text, - PRIMARY KEY ((tenant_id, user_id), id) -); - -CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_tenant_id ( - tenant_id timeuuid, - id timeuuid, - partition bigint, - customer_id timeuuid, - entity_id timeuuid, - entity_type text, - entity_name text, - user_id timeuuid, - user_name text, - action_type text, - action_data text, - action_status text, - action_failure_details text, - PRIMARY KEY ((tenant_id, partition), id) -); - -CREATE TABLE IF NOT EXISTS thingsboard.audit_log_by_tenant_id_partitions ( - tenant_id timeuuid, - partition bigint, - PRIMARY KEY (( tenant_id ), partition) -) WITH CLUSTERING ORDER BY ( partition ASC ) -AND compaction = { 'class' : 'LeveledCompactionStrategy' }; - -CREATE TABLE IF NOT EXISTS thingsboard.msg_queue ( - node_id timeuuid, - cluster_partition bigint, - ts_partition bigint, - ts bigint, - msg blob, - PRIMARY KEY ((node_id, cluster_partition, ts_partition), ts)) -WITH CLUSTERING ORDER BY (ts DESC) -AND compaction = { - 'class': 'org.apache.cassandra.db.compaction.DateTieredCompactionStrategy', - 'min_threshold': '5', - 'base_time_seconds': '43200', - 'max_window_size_seconds': '43200', - 'tombstone_threshold': '0.9', - 'unchecked_tombstone_compaction': 'true' -}; - -CREATE TABLE IF NOT EXISTS thingsboard.msg_ack_queue ( - node_id timeuuid, - cluster_partition bigint, - ts_partition bigint, - msg_id timeuuid, - PRIMARY KEY ((node_id, cluster_partition, ts_partition), msg_id)) -WITH CLUSTERING ORDER BY (msg_id DESC) -AND compaction = { - 'class': 'org.apache.cassandra.db.compaction.DateTieredCompactionStrategy', - 'min_threshold': '5', - 'base_time_seconds': '43200', - 'max_window_size_seconds': '43200', - 'tombstone_threshold': '0.9', - 'unchecked_tombstone_compaction': 'true' -}; - -CREATE TABLE IF NOT EXISTS thingsboard.processed_msg_partitions ( - node_id timeuuid, - cluster_partition bigint, - ts_partition bigint, - PRIMARY KEY ((node_id, cluster_partition), ts_partition)) -WITH CLUSTERING ORDER BY (ts_partition DESC) -AND compaction = { - 'class': 'org.apache.cassandra.db.compaction.DateTieredCompactionStrategy', - 'min_threshold': '5', - 'base_time_seconds': '43200', - 'max_window_size_seconds': '43200', - 'tombstone_threshold': '0.9', - 'unchecked_tombstone_compaction': 'true' -}; - -CREATE TABLE IF NOT EXISTS thingsboard.rule_chain ( - id uuid, - tenant_id uuid, - name text, - search_text text, - first_rule_node_id uuid, - root boolean, - debug_mode boolean, - configuration text, - additional_info text, - PRIMARY KEY (id, tenant_id) -); - -CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.rule_chain_by_tenant_and_search_text AS - SELECT * - from thingsboard.rule_chain - WHERE tenant_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL - PRIMARY KEY ( tenant_id, search_text, id ) - WITH CLUSTERING ORDER BY ( search_text ASC, id DESC ); - -CREATE TABLE IF NOT EXISTS thingsboard.rule_node ( - id uuid, - rule_chain_id uuid, - type text, - name text, - debug_mode boolean, - search_text text, - configuration text, - additional_info text, - PRIMARY KEY (id) -); diff --git a/dao/src/main/resources/sql/schema.sql b/dao/src/main/resources/sql/schema.sql deleted file mode 100644 index 91e77da503..0000000000 --- a/dao/src/main/resources/sql/schema.sql +++ /dev/null @@ -1,253 +0,0 @@ --- --- 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. --- - - -CREATE TABLE IF NOT EXISTS admin_settings ( - id varchar(31) NOT NULL CONSTRAINT admin_settings_pkey PRIMARY KEY, - json_value varchar, - key varchar(255) -); - -CREATE TABLE IF NOT EXISTS alarm ( - id varchar(31) NOT NULL CONSTRAINT alarm_pkey PRIMARY KEY, - ack_ts bigint, - clear_ts bigint, - additional_info varchar, - end_ts bigint, - originator_id varchar(31), - originator_type integer, - propagate boolean, - severity varchar(255), - start_ts bigint, - status varchar(255), - tenant_id varchar(31), - type varchar(255) -); - -CREATE TABLE IF NOT EXISTS asset ( - id varchar(31) NOT NULL CONSTRAINT asset_pkey PRIMARY KEY, - additional_info varchar, - customer_id varchar(31), - name varchar(255), - search_text varchar(255), - tenant_id varchar(31), - type varchar(255) -); - -CREATE TABLE IF NOT EXISTS audit_log ( - id varchar(31) NOT NULL CONSTRAINT audit_log_pkey PRIMARY KEY, - tenant_id varchar(31), - customer_id varchar(31), - entity_id varchar(31), - entity_type varchar(255), - entity_name varchar(255), - user_id varchar(31), - user_name varchar(255), - action_type varchar(255), - action_data varchar(1000000), - action_status varchar(255), - action_failure_details varchar(1000000) -); - -CREATE TABLE IF NOT EXISTS attribute_kv ( - entity_type varchar(255), - entity_id varchar(31), - attribute_type varchar(255), - attribute_key varchar(255), - bool_v boolean, - str_v varchar(10000000), - long_v bigint, - dbl_v double precision, - last_update_ts bigint, - CONSTRAINT attribute_kv_unq_key UNIQUE (entity_type, entity_id, attribute_type, attribute_key) -); - -CREATE TABLE IF NOT EXISTS component_descriptor ( - id varchar(31) NOT NULL CONSTRAINT component_descriptor_pkey PRIMARY KEY, - actions varchar(255), - clazz varchar, - configuration_descriptor varchar, - name varchar(255), - scope varchar(255), - search_text varchar(255), - type varchar(255) -); - -CREATE TABLE IF NOT EXISTS customer ( - id varchar(31) NOT NULL CONSTRAINT customer_pkey PRIMARY KEY, - additional_info varchar, - address varchar, - address2 varchar, - city varchar(255), - country varchar(255), - email varchar(255), - phone varchar(255), - search_text varchar(255), - state varchar(255), - tenant_id varchar(31), - title varchar(255), - zip varchar(255) -); - -CREATE TABLE IF NOT EXISTS dashboard ( - id varchar(31) NOT NULL CONSTRAINT dashboard_pkey PRIMARY KEY, - configuration varchar(10000000), - assigned_customers varchar(1000000), - search_text varchar(255), - tenant_id varchar(31), - title varchar(255) -); - -CREATE TABLE IF NOT EXISTS device ( - id varchar(31) NOT NULL CONSTRAINT device_pkey PRIMARY KEY, - additional_info varchar, - customer_id varchar(31), - type varchar(255), - name varchar(255), - search_text varchar(255), - tenant_id varchar(31) -); - -CREATE TABLE IF NOT EXISTS device_credentials ( - id varchar(31) NOT NULL CONSTRAINT device_credentials_pkey PRIMARY KEY, - credentials_id varchar, - credentials_type varchar(255), - credentials_value varchar, - device_id varchar(31) -); - -CREATE TABLE IF NOT EXISTS event ( - id varchar(31) NOT NULL CONSTRAINT event_pkey PRIMARY KEY, - body varchar, - entity_id varchar(31), - entity_type varchar(255), - event_type varchar(255), - event_uid varchar(255), - tenant_id varchar(31), - CONSTRAINT event_unq_key UNIQUE (tenant_id, entity_type, entity_id, event_type, event_uid) -); - -CREATE TABLE IF NOT EXISTS relation ( - from_id varchar(31), - from_type varchar(255), - to_id varchar(31), - to_type varchar(255), - relation_type_group varchar(255), - relation_type varchar(255), - additional_info varchar, - CONSTRAINT relation_unq_key UNIQUE (from_id, from_type, relation_type_group, relation_type, to_id, to_type) -); - -CREATE TABLE IF NOT EXISTS tb_user ( - id varchar(31) NOT NULL CONSTRAINT tb_user_pkey PRIMARY KEY, - additional_info varchar, - authority varchar(255), - customer_id varchar(31), - email varchar(255) UNIQUE, - first_name varchar(255), - last_name varchar(255), - search_text varchar(255), - tenant_id varchar(31) -); - -CREATE TABLE IF NOT EXISTS tenant ( - id varchar(31) NOT NULL CONSTRAINT tenant_pkey PRIMARY KEY, - additional_info varchar, - address varchar, - address2 varchar, - city varchar(255), - country varchar(255), - email varchar(255), - phone varchar(255), - region varchar(255), - search_text varchar(255), - state varchar(255), - title varchar(255), - zip varchar(255) -); - -CREATE TABLE IF NOT EXISTS ts_kv ( - entity_type varchar(255) NOT NULL, - entity_id varchar(31) NOT NULL, - key varchar(255) NOT NULL, - ts bigint NOT NULL, - bool_v boolean, - str_v varchar(10000000), - long_v bigint, - dbl_v double precision, - CONSTRAINT ts_kv_unq_key UNIQUE (entity_type, entity_id, key, ts) -); - -CREATE TABLE IF NOT EXISTS ts_kv_latest ( - entity_type varchar(255) NOT NULL, - entity_id varchar(31) NOT NULL, - key varchar(255) NOT NULL, - ts bigint NOT NULL, - bool_v boolean, - str_v varchar(10000000), - long_v bigint, - dbl_v double precision, - CONSTRAINT ts_kv_latest_unq_key UNIQUE (entity_type, entity_id, key) -); - -CREATE TABLE IF NOT EXISTS user_credentials ( - id varchar(31) NOT NULL CONSTRAINT user_credentials_pkey PRIMARY KEY, - activate_token varchar(255) UNIQUE, - enabled boolean, - password varchar(255), - reset_token varchar(255) UNIQUE, - user_id varchar(31) UNIQUE -); - -CREATE TABLE IF NOT EXISTS widget_type ( - id varchar(31) NOT NULL CONSTRAINT widget_type_pkey PRIMARY KEY, - alias varchar(255), - bundle_alias varchar(255), - descriptor varchar(1000000), - name varchar(255), - tenant_id varchar(31) -); - -CREATE TABLE IF NOT EXISTS widgets_bundle ( - id varchar(31) NOT NULL CONSTRAINT widgets_bundle_pkey PRIMARY KEY, - alias varchar(255), - search_text varchar(255), - tenant_id varchar(31), - title varchar(255) -); - -CREATE TABLE IF NOT EXISTS rule_chain ( - id varchar(31) NOT NULL CONSTRAINT rule_chain_pkey PRIMARY KEY, - additional_info varchar, - configuration varchar(10000000), - name varchar(255), - first_rule_node_id varchar(31), - root boolean, - debug_mode boolean, - search_text varchar(255), - tenant_id varchar(31) -); - -CREATE TABLE IF NOT EXISTS rule_node ( - id varchar(31) NOT NULL CONSTRAINT rule_node_pkey PRIMARY KEY, - rule_chain_id varchar(31), - additional_info varchar, - configuration varchar(10000000), - type varchar(255), - name varchar(255), - debug_mode boolean, - search_text varchar(255) -); diff --git a/dao/src/test/java/org/thingsboard/server/dao/JpaDaoTestSuite.java b/dao/src/test/java/org/thingsboard/server/dao/JpaDaoTestSuite.java index 48ba2fae68..a9d2cbc4f9 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/JpaDaoTestSuite.java +++ b/dao/src/test/java/org/thingsboard/server/dao/JpaDaoTestSuite.java @@ -30,7 +30,7 @@ public class JpaDaoTestSuite { @ClassRule public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema.sql", "sql/system-data.sql"), + Arrays.asList("sql/schema-ts.sql", "sql/schema-entities.sql", "sql/system-data.sql"), "sql/drop-all-tables.sql", "sql-test.properties" ); diff --git a/dao/src/test/java/org/thingsboard/server/dao/NoSqlDaoServiceTestSuite.java b/dao/src/test/java/org/thingsboard/server/dao/NoSqlDaoServiceTestSuite.java index f10462d77f..55c2f70f1d 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/NoSqlDaoServiceTestSuite.java +++ b/dao/src/test/java/org/thingsboard/server/dao/NoSqlDaoServiceTestSuite.java @@ -34,7 +34,9 @@ public class NoSqlDaoServiceTestSuite { @ClassRule public static CustomCassandraCQLUnit cassandraUnit = new CustomCassandraCQLUnit( - Arrays.asList(new ClassPathCQLDataSet("cassandra/schema.cql", false, false), + Arrays.asList( + new ClassPathCQLDataSet("cassandra/schema-ts.cql", false, false), + new ClassPathCQLDataSet("cassandra/schema-entities.cql", false, false), new ClassPathCQLDataSet("cassandra/system-data.cql", false, false), new ClassPathCQLDataSet("cassandra/system-test.cql", false, false)), "cassandra-test.yaml", 30000L); diff --git a/dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java b/dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java index 3f65184bfb..9e56d64aba 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java +++ b/dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java @@ -30,7 +30,7 @@ public class SqlDaoServiceTestSuite { @ClassRule public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema.sql", "sql/system-data.sql", "sql/system-test.sql"), + Arrays.asList("sql/schema-ts.sql", "sql/schema-entities.sql", "sql/system-data.sql", "sql/system-test.sql"), "sql/drop-all-tables.sql", "sql-test.properties" ); diff --git a/dao/src/test/resources/nosql-test.properties b/dao/src/test/resources/nosql-test.properties index e37e228b40..06a92faa01 100644 --- a/dao/src/test/resources/nosql-test.properties +++ b/dao/src/test/resources/nosql-test.properties @@ -1,4 +1,5 @@ -database.type=cassandra +database.entities.type=cassandra +database.ts.type=cassandra cassandra.queue.partitioning=HOURS cassandra.queue.ack.ttl=3600 diff --git a/dao/src/test/resources/sql-test.properties b/dao/src/test/resources/sql-test.properties index 1f34b98222..3357425fce 100644 --- a/dao/src/test/resources/sql-test.properties +++ b/dao/src/test/resources/sql-test.properties @@ -1,4 +1,5 @@ -database.type=sql +database.ts.type=sql +database.entities.type=sql sql.ts_inserts_executor_type=fixed sql.ts_inserts_fixed_thread_pool_size=10 diff --git a/docker/k8s/cassandra-setup.yaml b/docker/k8s/cassandra-setup.yaml index 381df77e65..03a2739446 100644 --- a/docker/k8s/cassandra-setup.yaml +++ b/docker/k8s/cassandra-setup.yaml @@ -30,7 +30,9 @@ spec: value: "cassandra-headless" - name : CASSANDRA_PORT value: "9042" - - name : DATABASE_TYPE + - name : DATABASE_ENTITIES_TYPE + value: "cassandra" + - name : DATABASE_TS_TYPE value: "cassandra" - name : CASSANDRA_URL value: "cassandra-headless:9042" diff --git a/docker/k8s/cassandra-upgrade.yaml b/docker/k8s/cassandra-upgrade.yaml index a78136ec41..9276776678 100644 --- a/docker/k8s/cassandra-upgrade.yaml +++ b/docker/k8s/cassandra-upgrade.yaml @@ -30,7 +30,9 @@ spec: value: "cassandra-headless" - name : CASSANDRA_PORT value: "9042" - - name : DATABASE_TYPE + - name : DATABASE_ENTITIES_TYPE + value: "cassandra" + - name : DATABASE_TS_TYPE value: "cassandra" - name : CASSANDRA_URL value: "cassandra-headless:9042" diff --git a/docker/k8s/tb.yaml b/docker/k8s/tb.yaml index f38e1f12b1..741bbe0f26 100644 --- a/docker/k8s/tb.yaml +++ b/docker/k8s/tb.yaml @@ -120,7 +120,12 @@ spec: configMapKeyRef: name: tb-config key: cassandra.url - - name: DATABASE_TYPE + - name: DATABASE_ENTITIES_TYPE + valueFrom: + configMapKeyRef: + name: tb-config + key: database.type + - name: DATABASE_TS_TYPE valueFrom: configMapKeyRef: name: tb-config diff --git a/docker/tb.env b/docker/tb.env index 76afc29962..bc92de5c8b 100644 --- a/docker/tb.env +++ b/docker/tb.env @@ -8,7 +8,8 @@ COAP_BIND_PORT=5683 ZOOKEEPER_URL=zk:2181 # type of database to use: sql[DEFAULT] or cassandra -DATABASE_TYPE=sql +DATABASE_TS_TYPE=sql +DATABASE_ENTITIES_TYPE=sql # cassandra db config CASSANDRA_URL=cassandra:9042 diff --git a/docker/tb/run-application.sh b/docker/tb/run-application.sh index a2a1e2beba..e6b59f9aee 100755 --- a/docker/tb/run-application.sh +++ b/docker/tb/run-application.sh @@ -23,7 +23,7 @@ printenv | awk -F "=" '{print "export " $1 "='\''" $2 "'\''"}' >> /usr/share/thi cat /usr/share/thingsboard/conf/thingsboard.conf -if [ "$DATABASE_TYPE" == "cassandra" ]; then +if [ "$DATABASE_ENTITIES_TYPE" == "cassandra" ]; then until nmap $CASSANDRA_HOST -p $CASSANDRA_PORT | grep "$CASSANDRA_PORT/tcp open\|filtered" do echo "Wait for cassandra db to start..." @@ -31,7 +31,7 @@ if [ "$DATABASE_TYPE" == "cassandra" ]; then done fi -if [ "$DATABASE_TYPE" == "sql" ]; then +if [ "$DATABASE_ENTITIES_TYPE" == "sql" ]; then if [ "$SPRING_DRIVER_CLASS_NAME" == "org.postgresql.Driver" ]; then until nmap $POSTGRES_HOST -p $POSTGRES_PORT | grep "$POSTGRES_PORT/tcp open" do From 014ed4f97939583246e3f0032408276bdf142525 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Thu, 20 Sep 2018 17:08:03 +0300 Subject: [PATCH 099/118] Fixed tests --- .../service/install/CassandraEntityDatabaseSchemaService.java | 2 ++ .../service/install/CassandraTsDatabaseSchemaService.java | 2 ++ .../server/service/install/SqlEntityDatabaseSchemaService.java | 2 ++ .../server/service/install/SqlTsDatabaseSchemaService.java | 2 ++ 4 files changed, 8 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraEntityDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraEntityDatabaseSchemaService.java index 7937ef23be..b492a51cbc 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/CassandraEntityDatabaseSchemaService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraEntityDatabaseSchemaService.java @@ -15,11 +15,13 @@ */ package org.thingsboard.server.service.install; +import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; import org.thingsboard.server.dao.util.NoSqlDao; @Service @NoSqlDao +@Profile("install") public class CassandraEntityDatabaseSchemaService extends CassandraAbstractDatabaseSchemaService implements EntityDatabaseSchemaService { public CassandraEntityDatabaseSchemaService() { diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseSchemaService.java index ba18b57ff1..1a3a2e429b 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseSchemaService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseSchemaService.java @@ -15,11 +15,13 @@ */ package org.thingsboard.server.service.install; +import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; import org.thingsboard.server.dao.util.NoSqlTsDao; @Service @NoSqlTsDao +@Profile("install") public class CassandraTsDatabaseSchemaService extends CassandraAbstractDatabaseSchemaService implements TsDatabaseSchemaService { public CassandraTsDatabaseSchemaService() { diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlEntityDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlEntityDatabaseSchemaService.java index 16453c6ebb..bfd371b28a 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlEntityDatabaseSchemaService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlEntityDatabaseSchemaService.java @@ -15,11 +15,13 @@ */ package org.thingsboard.server.service.install; +import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; import org.thingsboard.server.dao.util.SqlDao; @Service @SqlDao +@Profile("install") public class SqlEntityDatabaseSchemaService extends SqlAbstractDatabaseSchemaService implements EntityDatabaseSchemaService { public SqlEntityDatabaseSchemaService() { diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlTsDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlTsDatabaseSchemaService.java index 82daf904df..03a35178bf 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlTsDatabaseSchemaService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlTsDatabaseSchemaService.java @@ -15,11 +15,13 @@ */ package org.thingsboard.server.service.install; +import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; import org.thingsboard.server.dao.util.SqlTsDao; @Service @SqlTsDao +@Profile("install") public class SqlTsDatabaseSchemaService extends SqlAbstractDatabaseSchemaService implements TsDatabaseSchemaService { public SqlTsDatabaseSchemaService() { From 56397e0d9000665e37607738ef03c6025621381a Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Fri, 21 Sep 2018 17:37:04 +0300 Subject: [PATCH 100/118] Added several checks for equality to null --- .../server/dao/entityview/EntityViewServiceImpl.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) 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 dd3e61d611..8647af7fe4 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 @@ -102,14 +102,16 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti log.trace("Executing save entity view [{}]", entityView); entityViewValidator.validate(entityView); EntityView savedEntityView = entityViewDao.save(entityView); - copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs()); - copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SERVER_SCOPE, savedEntityView.getKeys().getAttributes().getSs()); - copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SHARED_SCOPE, savedEntityView.getKeys().getAttributes().getSh()); + if (savedEntityView.getKeys() != null) { + copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs()); + copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SERVER_SCOPE, savedEntityView.getKeys().getAttributes().getSs()); + copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SHARED_SCOPE, savedEntityView.getKeys().getAttributes().getSh()); + } return savedEntityView; } private void copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection keys) { - if (!keys.isEmpty()) { + if (keys != null && !keys.isEmpty()) { ListenableFuture> getAttrFuture = attributesService.find(entityView.getEntityId(), scope, keys); Futures.addCallback(getAttrFuture, new FutureCallback>() { @Override From b45662c630b342fb9995e424a65b80daddee13ba Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Fri, 21 Sep 2018 17:38:23 +0300 Subject: [PATCH 101/118] Added test for checking the copy attributes --- .../BaseEntityViewControllerTest.java | 163 ++++++++++++------ 1 file changed, 109 insertions(+), 54 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index b368ea1989..80e384afdf 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -18,10 +18,12 @@ package org.thingsboard.server.controller; import com.datastax.driver.core.utils.UUIDs; import com.fasterxml.jackson.core.type.TypeReference; import org.apache.commons.lang3.RandomStringUtils; +import org.eclipse.paho.client.mqttv3.MqttAsyncClient; +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; +import org.eclipse.paho.client.mqttv3.MqttMessage; import org.junit.After; import org.junit.Assert; import org.junit.Before; -import org.junit.Test; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityView; @@ -33,14 +35,21 @@ import org.thingsboard.server.common.data.objects.TelemetryEntityView; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.dao.model.ModelConstants; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; @@ -50,12 +59,11 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes private Tenant savedTenant; private User tenantAdmin; private Device testDevice; - private TelemetryEntityView keys; + private TelemetryEntityView telemetry; @Before public void beforeTest() throws Exception { loginSysAdmin(); - idComparator = new IdComparator<>(); savedTenant = doPost("/api/tenant", getNewTenant("My tenant"), Tenant.class); @@ -67,7 +75,6 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes tenantAdmin.setEmail("tenant2@thingsboard.org"); tenantAdmin.setFirstName("Joe"); tenantAdmin.setLastName("Downs"); - tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); Device device = new Device(); @@ -75,12 +82,12 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes device.setType("default"); testDevice = doPost("/api/device", device, Device.class); - keys = new TelemetryEntityView( - Arrays.asList("109L", "209L"), + telemetry = new TelemetryEntityView( + Arrays.asList("109", "209", "309"), new AttributesEntityView( - Arrays.asList("caKey1", "caKey2"), - Arrays.asList("saKey1", "saKey2", "saKey3"), - Arrays.asList("shKey1", "shKey2", "shKey3", "shKey4"))); + Arrays.asList("caValue1", "caValue2", "caValue3", "caValue4"), + Arrays.asList("saValue1", "saValue2", "saValue3", "saValue4"), + Arrays.asList("shValue1", "shValue2", "shValue3", "shValue4"))); } @After @@ -91,37 +98,37 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes .andExpect(status().isOk()); } - @Test + //@Test public void testFindEntityViewById() throws Exception { - EntityView savedView = doPost("/api/entityView", getNewEntityView("Test entity view"), EntityView.class); + EntityView savedView = getNewSavedEntityView("Test entity view"); EntityView foundView = doGet("/api/entityView/" + savedView.getId().getId().toString(), EntityView.class); Assert.assertNotNull(foundView); - Assert.assertEquals(savedView, foundView); + assertEquals(savedView, foundView); } - @Test + //@Test public void testSaveEntityView() throws Exception { - EntityView savedView = doPost("/api/entityView", getNewEntityView("Test entity view"), EntityView.class); + EntityView savedView = getNewSavedEntityView("Test entity view"); Assert.assertNotNull(savedView); Assert.assertNotNull(savedView.getId()); Assert.assertTrue(savedView.getCreatedTime() > 0); - Assert.assertEquals(savedTenant.getId(), savedView.getTenantId()); + assertEquals(savedTenant.getId(), savedView.getTenantId()); Assert.assertNotNull(savedView.getCustomerId()); - Assert.assertEquals(NULL_UUID, savedView.getCustomerId().getId()); - Assert.assertEquals(savedView.getName(), savedView.getName()); + assertEquals(NULL_UUID, savedView.getCustomerId().getId()); + assertEquals(savedView.getName(), savedView.getName()); savedView.setName("New test entity view"); doPost("/api/entityView", savedView, EntityView.class); EntityView foundEntityView = doGet("/api/entityView/" + savedView.getId().getId().toString(), EntityView.class); - Assert.assertEquals(foundEntityView.getName(), savedView.getName()); - Assert.assertEquals(foundEntityView.getKeys(), keys); + assertEquals(foundEntityView.getName(), savedView.getName()); + assertEquals(foundEntityView.getKeys(), telemetry); } - @Test + //@Test public void testDeleteEntityView() throws Exception { - EntityView view = getNewEntityView("Test entity view"); + EntityView view = getNewSavedEntityView("Test entity view"); Customer customer = doPost("/api/customer", getNewCustomer("My customer"), Customer.class); view.setCustomerId(customer.getId()); EntityView savedView = doPost("/api/entityView", view, EntityView.class); @@ -133,16 +140,16 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes .andExpect(status().isNotFound()); } - @Test + //@Test public void testSaveEntityViewWithEmptyName() throws Exception { doPost("/api/entityView", new EntityView()) .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString("Entity view name should be specified!"))); } - @Test + //@Test public void testAssignAndUnAssignedEntityViewToCustomer() throws Exception { - EntityView view = getNewEntityView("Test entity view"); + EntityView view = getNewSavedEntityView("Test entity view"); Customer savedCustomer = doPost("/api/customer", getNewCustomer("My customer"), Customer.class); view.setCustomerId(savedCustomer.getId()); EntityView savedView = doPost("/api/entityView", view, EntityView.class); @@ -150,26 +157,26 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes EntityView assignedView = doPost( "/api/customer/" + savedCustomer.getId().getId().toString() + "/entityView/" + savedView.getId().getId().toString(), EntityView.class); - Assert.assertEquals(savedCustomer.getId(), assignedView.getCustomerId()); + assertEquals(savedCustomer.getId(), assignedView.getCustomerId()); EntityView foundView = doGet("/api/entityView/" + savedView.getId().getId().toString(), EntityView.class); - Assert.assertEquals(savedCustomer.getId(), foundView.getCustomerId()); + assertEquals(savedCustomer.getId(), foundView.getCustomerId()); EntityView unAssignedView = doDelete("/api/customer/entityView/" + savedView.getId().getId().toString(), EntityView.class); - Assert.assertEquals(ModelConstants.NULL_UUID, unAssignedView.getCustomerId().getId()); + assertEquals(ModelConstants.NULL_UUID, unAssignedView.getCustomerId().getId()); foundView = doGet("/api/entityView/" + savedView.getId().getId().toString(), EntityView.class); - Assert.assertEquals(ModelConstants.NULL_UUID, foundView.getCustomerId().getId()); + assertEquals(ModelConstants.NULL_UUID, foundView.getCustomerId().getId()); } - @Test + //@Test public void testAssignEntityViewToNonExistentCustomer() throws Exception { - EntityView savedView = doPost("/api/entityView", getNewEntityView("Test entity view"), EntityView.class); + EntityView savedView = getNewSavedEntityView("Test entity view"); doPost("/api/customer/" + UUIDs.timeBased().toString() + "/device/" + savedView.getId().getId().toString()) .andExpect(status().isNotFound()); } - @Test + //@Test public void testAssignEntityViewToCustomerFromDifferentTenant() throws Exception { loginSysAdmin(); @@ -190,8 +197,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes login(tenantAdmin.getEmail(), "testPassword1"); - EntityView view = getNewEntityView("Test entity view"); - EntityView savedView = doPost("/api/entityView", view, EntityView.class); + EntityView savedView = getNewSavedEntityView("Test entity view"); doPost("/api/customer/" + savedCustomer.getId().getId().toString() + "/entityView/" + savedView.getId().getId().toString()) .andExpect(status().isForbidden()); @@ -202,7 +208,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes .andExpect(status().isOk()); } - @Test + //@Test public void testGetCustomerEntityViews() throws Exception { CustomerId customerId = doPost("/api/customer", getNewCustomer("Test customer"), Customer.class).getId(); String urlTemplate = "/api/customer/" + customerId.getId().toString() + "/entityViews?"; @@ -210,7 +216,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes List views = new ArrayList<>(); for (int i = 0; i < 128; i++) { views.add(doPost("/api/customer/" + customerId.getId().toString() + "/entityView/" - + getNewEntityView("Test entity view " + i).getId().getId().toString(), EntityView.class)); + + getNewSavedEntityView("Test entity view " + i).getId().getId().toString(), EntityView.class)); } List loadedViews = loadListOf(new TextPageLink(23), urlTemplate); @@ -218,10 +224,10 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes Collections.sort(views, idComparator); Collections.sort(loadedViews, idComparator); - Assert.assertEquals(views, loadedViews); + assertEquals(views, loadedViews); } - @Test + //@Test public void testGetCustomerEntityViewsByName() throws Exception { CustomerId customerId = doPost("/api/customer", getNewCustomer("Test customer"), Customer.class).getId(); String urlTemplate = "/api/customer/" + customerId.getId().toString() + "/entityViews?"; @@ -232,7 +238,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes List loadedNamesOfView1 = loadListOf(new TextPageLink(15, name1), urlTemplate); Collections.sort(namesOfView1, idComparator); Collections.sort(loadedNamesOfView1, idComparator); - Assert.assertEquals(namesOfView1, loadedNamesOfView1); + assertEquals(namesOfView1, loadedNamesOfView1); String name2 = "Entity view name2"; List NamesOfView2 = fillListOf(143, name2, "/api/customer/" + customerId.getId().toString() @@ -240,7 +246,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes List loadedNamesOfView2 = loadListOf(new TextPageLink(4, name2), urlTemplate); Collections.sort(NamesOfView2, idComparator); Collections.sort(loadedNamesOfView2, idComparator); - Assert.assertEquals(NamesOfView2, loadedNamesOfView2); + assertEquals(NamesOfView2, loadedNamesOfView2); for (EntityView view : loadedNamesOfView1) { doDelete("/api/customer/entityView/" + view.getId().getId().toString()).andExpect(status().isOk()); @@ -249,7 +255,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes new TypeReference>() { }, new TextPageLink(4, name1)); Assert.assertFalse(pageData.hasNext()); - Assert.assertEquals(0, pageData.getData().size()); + assertEquals(0, pageData.getData().size()); for (EntityView view : loadedNamesOfView2) { doDelete("/api/customer/entityView/" + view.getId().getId().toString()).andExpect(status().isOk()); @@ -258,39 +264,39 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes }, new TextPageLink(4, name2)); Assert.assertFalse(pageData.hasNext()); - Assert.assertEquals(0, pageData.getData().size()); + assertEquals(0, pageData.getData().size()); } - @Test + //@Test public void testGetTenantEntityViews() throws Exception { List views = new ArrayList<>(); for (int i = 0; i < 178; i++) { - views.add(doPost("/api/entityView/", getNewEntityView("Test entity view" + i), EntityView.class)); + views.add(getNewSavedEntityView("Test entity view" + i)); } List loadedViews = loadListOf(new TextPageLink(23), "/api/tenant/entityViews?"); Collections.sort(views, idComparator); Collections.sort(loadedViews, idComparator); - Assert.assertEquals(views, loadedViews); + assertEquals(views, loadedViews); } - @Test + //@Test public void testGetTenantEntityViewsByName() throws Exception { String name1 = "Entity view name1"; List namesOfView1 = fillListOf(143, name1); List loadedNamesOfView1 = loadListOf(new TextPageLink(15, name1), "/api/tenant/entityViews?"); Collections.sort(namesOfView1, idComparator); Collections.sort(loadedNamesOfView1, idComparator); - Assert.assertEquals(namesOfView1, loadedNamesOfView1); + assertEquals(namesOfView1, loadedNamesOfView1); String name2 = "Entity view name2"; List NamesOfView2 = fillListOf(75, name2); List loadedNamesOfView2 = loadListOf(new TextPageLink(4, name2), "/api/tenant/entityViews?"); Collections.sort(NamesOfView2, idComparator); Collections.sort(loadedNamesOfView2, idComparator); - Assert.assertEquals(NamesOfView2, loadedNamesOfView2); + assertEquals(NamesOfView2, loadedNamesOfView2); for (EntityView view : loadedNamesOfView1) { doDelete("/api/entityView/" + view.getId().getId().toString()).andExpect(status().isOk()); @@ -299,7 +305,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes new TypeReference>() { }, new TextPageLink(4, name1)); Assert.assertFalse(pageData.hasNext()); - Assert.assertEquals(0, pageData.getData().size()); + assertEquals(0, pageData.getData().size()); for (EntityView view : loadedNamesOfView2) { doDelete("/api/entityView/" + view.getId().getId().toString()).andExpect(status().isOk()); @@ -308,17 +314,66 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes }, new TextPageLink(4, name2)); Assert.assertFalse(pageData.hasNext()); - Assert.assertEquals(0, pageData.getData().size()); + assertEquals(0, pageData.getData().size()); } - private EntityView getNewEntityView(String name) throws Exception { + //@Test + public void testTheCopyOfAttrsThatMatchWithDeviceCriteriaForTheView() throws Exception { + + String viewDeviceId = testDevice.getId().getId().toString(); + DeviceCredentials deviceCredentials + = doGet("/api/device/" + viewDeviceId + "/credentials", DeviceCredentials.class); + + assertEquals(testDevice.getId(), deviceCredentials.getDeviceId()); + + String accessToken = deviceCredentials.getCredentialsId(); + assertNotNull(accessToken); + + String clientId = MqttAsyncClient.generateClientId(); + MqttAsyncClient client = new MqttAsyncClient("tcp://localhost:1883", clientId); + + MqttConnectOptions options = new MqttConnectOptions(); + options.setUserName(accessToken); + client.connect(options); + Thread.sleep(3000); + + MqttMessage message = new MqttMessage(); + message.setPayload(("{\"caValue1\":\"value1\", \"caValue2\":true, \"caValue3\":42.0, \"caValue4\":73}").getBytes()); + client.publish("v1/devices/me/attributes", message); + Thread.sleep(1000); + + List actualTelemetry = + doGetAsync("/api/plugins/telemetry/DEVICE/" + viewDeviceId + "/keys/attributes", List.class); + Set actualTelemetrySet = new HashSet<>(actualTelemetry); + + List expectedActualTelemetry = Arrays.asList("caValue1", "caValue2", "caValue3", "caValue4"); + Set expectedActualTelemetrySet = new HashSet<>(expectedActualTelemetry); + assertTrue(actualTelemetrySet.containsAll(expectedActualTelemetrySet)); + Thread.sleep(1000); + + EntityView savedView = getNewSavedEntityView("Test entity view"); + String urlOfTelemetryValues = "/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + + "/values/attributes?keys=" + String.join(",", actualTelemetrySet); + List> values = doGetAsync(urlOfTelemetryValues, List.class); + + assertEquals("value1", getValueOfMap(values, "caValue1")); + assertEquals(true, getValueOfMap(values, "caValue2")); + assertEquals(42.0, getValueOfMap(values, "caValue3")); + assertEquals(73, getValueOfMap(values, "caValue4")); + } + + private Object getValueOfMap(List> values, String stringValue) { + return values.stream() + .filter(value -> value.get("key").equals(stringValue)) + .findFirst().get().get("value"); + } + + private EntityView getNewSavedEntityView(String name) throws Exception { EntityView view = new EntityView(); view.setEntityId(testDevice.getId()); view.setTenantId(savedTenant.getId()); view.setName(name); - - view.setKeys(keys); - + view.setKeys(telemetry); return doPost("/api/entityView", view, EntityView.class); } @@ -347,7 +402,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes for (int i = 0; i < limit; i++) { String fullName = partOfName + ' ' + RandomStringUtils.randomAlphanumeric(15); fullName = i % 2 == 0 ? fullName.toLowerCase() : fullName.toUpperCase(); - EntityView view = getNewEntityView(fullName); + EntityView view = getNewSavedEntityView(fullName); Customer customer = getNewCustomer("Test customer " + String.valueOf(Math.random())); view.setCustomerId(doPost("/api/customer", customer, Customer.class).getId()); viewNames.add(doPost("/api/entityView", view, EntityView.class)); From 584bb763ca30adab744d45acd2c5ac876c99dcc0 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Fri, 21 Sep 2018 18:23:31 +0300 Subject: [PATCH 102/118] Fixed annotations @Test --- .../BaseEntityViewControllerTest.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index 80e384afdf..9dc13a8d37 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -24,6 +24,7 @@ import org.eclipse.paho.client.mqttv3.MqttMessage; import org.junit.After; import org.junit.Assert; import org.junit.Before; +import org.junit.Test; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityView; @@ -98,7 +99,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes .andExpect(status().isOk()); } - //@Test + @Test public void testFindEntityViewById() throws Exception { EntityView savedView = getNewSavedEntityView("Test entity view"); EntityView foundView = doGet("/api/entityView/" + savedView.getId().getId().toString(), EntityView.class); @@ -106,7 +107,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes assertEquals(savedView, foundView); } - //@Test + @Test public void testSaveEntityView() throws Exception { EntityView savedView = getNewSavedEntityView("Test entity view"); @@ -126,7 +127,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes assertEquals(foundEntityView.getKeys(), telemetry); } - //@Test + @Test public void testDeleteEntityView() throws Exception { EntityView view = getNewSavedEntityView("Test entity view"); Customer customer = doPost("/api/customer", getNewCustomer("My customer"), Customer.class); @@ -140,14 +141,14 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes .andExpect(status().isNotFound()); } - //@Test + @Test public void testSaveEntityViewWithEmptyName() throws Exception { doPost("/api/entityView", new EntityView()) .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString("Entity view name should be specified!"))); } - //@Test + @Test public void testAssignAndUnAssignedEntityViewToCustomer() throws Exception { EntityView view = getNewSavedEntityView("Test entity view"); Customer savedCustomer = doPost("/api/customer", getNewCustomer("My customer"), Customer.class); @@ -169,14 +170,14 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes assertEquals(ModelConstants.NULL_UUID, foundView.getCustomerId().getId()); } - //@Test + @Test public void testAssignEntityViewToNonExistentCustomer() throws Exception { EntityView savedView = getNewSavedEntityView("Test entity view"); doPost("/api/customer/" + UUIDs.timeBased().toString() + "/device/" + savedView.getId().getId().toString()) .andExpect(status().isNotFound()); } - //@Test + @Test public void testAssignEntityViewToCustomerFromDifferentTenant() throws Exception { loginSysAdmin(); @@ -208,7 +209,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes .andExpect(status().isOk()); } - //@Test + @Test public void testGetCustomerEntityViews() throws Exception { CustomerId customerId = doPost("/api/customer", getNewCustomer("Test customer"), Customer.class).getId(); String urlTemplate = "/api/customer/" + customerId.getId().toString() + "/entityViews?"; @@ -227,7 +228,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes assertEquals(views, loadedViews); } - //@Test + @Test public void testGetCustomerEntityViewsByName() throws Exception { CustomerId customerId = doPost("/api/customer", getNewCustomer("Test customer"), Customer.class).getId(); String urlTemplate = "/api/customer/" + customerId.getId().toString() + "/entityViews?"; @@ -267,7 +268,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes assertEquals(0, pageData.getData().size()); } - //@Test + @Test public void testGetTenantEntityViews() throws Exception { List views = new ArrayList<>(); @@ -282,7 +283,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes assertEquals(views, loadedViews); } - //@Test + @Test public void testGetTenantEntityViewsByName() throws Exception { String name1 = "Entity view name1"; List namesOfView1 = fillListOf(143, name1); @@ -317,7 +318,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes assertEquals(0, pageData.getData().size()); } - //@Test + @Test public void testTheCopyOfAttrsThatMatchWithDeviceCriteriaForTheView() throws Exception { String viewDeviceId = testDevice.getId().getId().toString(); From 4489440ae341615daf32c024c39caedca28bc670 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 24 Sep 2018 14:55:49 +0300 Subject: [PATCH 103/118] Were renamed variables --- .../controller/BaseEntityViewControllerTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index 9dc13a8d37..0daaeca72f 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -343,18 +343,18 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes client.publish("v1/devices/me/attributes", message); Thread.sleep(1000); - List actualTelemetry = + List actualAttributes = doGetAsync("/api/plugins/telemetry/DEVICE/" + viewDeviceId + "/keys/attributes", List.class); - Set actualTelemetrySet = new HashSet<>(actualTelemetry); + Set actualAttributesSet = new HashSet<>(actualAttributes); - List expectedActualTelemetry = Arrays.asList("caValue1", "caValue2", "caValue3", "caValue4"); - Set expectedActualTelemetrySet = new HashSet<>(expectedActualTelemetry); - assertTrue(actualTelemetrySet.containsAll(expectedActualTelemetrySet)); + List expectedActualAttributes = Arrays.asList("caValue1", "caValue2", "caValue3", "caValue4"); + Set expectedActualAttributesSet = new HashSet<>(expectedActualAttributes); + assertTrue(actualAttributesSet.containsAll(expectedActualAttributesSet)); Thread.sleep(1000); EntityView savedView = getNewSavedEntityView("Test entity view"); String urlOfTelemetryValues = "/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + - "/values/attributes?keys=" + String.join(",", actualTelemetrySet); + "/values/attributes?keys=" + String.join(",", actualAttributesSet); List> values = doGetAsync(urlOfTelemetryValues, List.class); assertEquals("value1", getValueOfMap(values, "caValue1")); From 2269656b095340b4d2892bfc4fc31cf483121663 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Tue, 25 Sep 2018 18:57:04 +0300 Subject: [PATCH 104/118] Were fixed --- .../server/controller/BaseController.java | 6 +- .../controller/EntityViewController.java | 26 +-- .../entityview/CassandraEntityViewDao.java | 2 +- .../server/dao/entityview/EntityViewDao.java | 2 +- .../dao/entityview/EntityViewService.java | 19 +- .../dao/entityview/EntityViewServiceImpl.java | 210 +++++++++++------- .../dao/sql/entityview/JpaEntityViewDao.java | 2 +- .../TbCopyAttributesToEntityViewNode.java | 59 +++-- 8 files changed, 184 insertions(+), 142 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index af62e04cff..84a8151316 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -318,7 +318,7 @@ public abstract class BaseController { checkUserId(new UserId(entityId.getId())); return; case ENTITY_VIEW: - checkEntityView(entityViewService.findEntityViewById(new EntityViewId(entityId.getId()))); + checkEntityViewId(entityViewService.findEntityViewById(new EntityViewId(entityId.getId()))); return; default: throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType()); @@ -351,14 +351,14 @@ public abstract class BaseController { try { validateId(entityViewId, "Incorrect entityViewId " + entityViewId); EntityView entityView = entityViewService.findEntityViewById(entityViewId); - checkEntityView(entityView); + checkEntityViewId(entityView); return entityView; } catch (Exception e) { throw handleException(e, false); } } - protected void checkEntityView(EntityView entityView) throws ThingsboardException { + protected void checkEntityViewId(EntityView entityView) throws ThingsboardException { checkNotNull(entityView); checkTenantId(entityView.getTenantId()); if (entityView.getCustomerId() != null && !entityView.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { 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 26a48daff6..e6f149e05c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java @@ -17,7 +17,14 @@ package org.thingsboard.server.controller; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; @@ -49,13 +56,10 @@ public class EntityViewController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/entityView/{entityViewId}", method = RequestMethod.GET) @ResponseBody - public EntityView getEntityViewById(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) - throws ThingsboardException { - + public EntityView getEntityViewById(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { checkParameter(ENTITY_VIEW_ID, strEntityViewId); try { - EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); - return checkEntityViewId(entityViewId); + return checkEntityViewId(new EntityViewId(toUUID(strEntityViewId))); } catch (Exception e) { throw handleException(e); } @@ -70,13 +74,10 @@ public class EntityViewController extends BaseController { EntityView savedEntityView = checkNotNull(entityViewService.saveEntityView(entityView)); logEntityAction(savedEntityView.getId(), savedEntityView, null, entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); - return savedEntityView; - } catch (Exception e) { logEntityAction(emptyId(EntityType.ENTITY_VIEW), entityView, null, entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e); - throw handleException(e); } } @@ -90,7 +91,6 @@ public class EntityViewController extends BaseController { EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); EntityView entityView = checkEntityViewId(entityViewId); entityViewService.deleteEntityView(entityViewId); - logEntityAction(entityViewId, entityView, entityView.getCustomerId(), ActionType.DELETED,null, strEntityViewId); } catch (Exception e) { @@ -117,11 +117,9 @@ public class EntityViewController extends BaseController { checkEntityViewId(entityViewId); EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToCustomer(entityViewId, customerId)); - logEntityAction(entityViewId, savedEntityView, savedEntityView.getCustomerId(), ActionType.ASSIGNED_TO_CUSTOMER, null, strEntityViewId, strCustomerId, customer.getName()); - return savedEntityView; } catch (Exception e) { logEntityAction(emptyId(EntityType.ENTITY_VIEW), null, @@ -143,9 +141,7 @@ public class EntityViewController extends BaseController { throw new IncorrectParameterException("Entity View isn't assigned to any customer!"); } Customer customer = checkCustomerId(entityView.getCustomerId()); - EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromCustomer(entityViewId)); - logEntityAction(entityViewId, entityView, entityView.getCustomerId(), ActionType.UNASSIGNED_FROM_CUSTOMER, null, strEntityViewId, customer.getId().toString(), customer.getName()); @@ -208,7 +204,7 @@ public class EntityViewController extends BaseController { List entityViews = checkNotNull(entityViewService.findEntityViewsByQuery(query).get()); entityViews = entityViews.stream().filter(entityView -> { try { - checkEntityView(entityView); + checkEntityViewId(entityView); return true; } catch (ThingsboardException e) { return false; 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 e866bc89b8..395f9022b0 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 @@ -78,7 +78,7 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao findEntityViewByTenantId(UUID tenantId, TextPageLink pageLink) { + public List findEntityViewsByTenantId(UUID tenantId, TextPageLink pageLink) { log.debug("Try to find entity views by tenantId [{}] and pageLink [{}]", tenantId, pageLink); List entityViewEntities = findPageWithTextSearch(ENTITY_VIEW_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, 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 742cb92d90..ba433855e2 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 @@ -45,7 +45,7 @@ public interface EntityViewDao extends Dao { * @param pageLink the page link * @return the list of entity view objects */ - List findEntityViewByTenantId(UUID tenantId, TextPageLink pageLink); + List findEntityViewsByTenantId(UUID tenantId, TextPageLink pageLink); /** * Find entity views by tenantId and entity view name. 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 89b7e2f85c..19f326c0bc 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 @@ -32,28 +32,27 @@ import java.util.List; */ public interface EntityViewService { - EntityView findEntityViewById(EntityViewId entityViewId); - EntityView saveEntityView(EntityView entityView); EntityView assignEntityViewToCustomer(EntityViewId entityViewId, CustomerId customerId); EntityView unassignEntityViewFromCustomer(EntityViewId entityViewId); - void deleteEntityView(EntityViewId entityViewId); + void unassignCustomerEntityViews(TenantId tenantId, CustomerId customerId); - TextPageData findEntityViewByTenantId(TenantId tenantId, TextPageLink pageLink); + EntityView findEntityViewById(EntityViewId entityViewId); - void deleteEntityViewsByTenantId(TenantId tenantId); + TextPageData findEntityViewByTenantId(TenantId tenantId, TextPageLink pageLink); - TextPageData findEntityViewsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, - TextPageLink pageLink); + TextPageData findEntityViewsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink); - void unassignCustomerEntityViews(TenantId tenantId, CustomerId customerId); + ListenableFuture> findEntityViewsByQuery(EntityViewSearchQuery query); ListenableFuture findEntityViewByIdAsync(EntityViewId entityViewId); - ListenableFuture> findEntityViewsByQuery(EntityViewSearchQuery query); - ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId); + + void deleteEntityView(EntityViewId entityViewId); + + void deleteEntityViewsByTenantId(TenantId tenantId); } 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 8647af7fe4..79ceff2351 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 @@ -24,7 +24,6 @@ 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.DataConstants; @@ -41,6 +40,7 @@ import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; +import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.customer.CustomerDao; import org.thingsboard.server.dao.entity.AbstractEntityService; @@ -54,13 +54,14 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.UUID; +import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; 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; -import static org.thingsboard.server.dao.service.Validator.validateString; /** * Created by Victor Basanets on 8/28/2017. @@ -73,6 +74,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti public static final String INCORRECT_PAGE_LINK = "Incorrect page link "; public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId "; public static final String INCORRECT_ENTITY_VIEW_ID = "Incorrect entityViewId "; + private static final int DEFAULT_LIMIT = 100; @Autowired private EntityViewDao entityViewDao; @@ -89,13 +91,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Autowired private CacheManager cacheManager; - @Override - public EntityView findEntityViewById(EntityViewId entityViewId) { - log.trace("Executing findEntityViewById [{}]", entityViewId); - validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); - return entityViewDao.findById(entityViewId.getId()); - } - @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityView.tenantId, #entityView.name}") @Override public EntityView saveEntityView(EntityView entityView) { @@ -110,41 +105,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti return savedEntityView; } - private void copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection keys) { - if (keys != null && !keys.isEmpty()) { - ListenableFuture> getAttrFuture = attributesService.find(entityView.getEntityId(), scope, keys); - Futures.addCallback(getAttrFuture, new FutureCallback>() { - @Override - public void onSuccess(@Nullable List attributeKvEntries) { - if (attributeKvEntries != null && !attributeKvEntries.isEmpty()) { - List filteredAttributes = - attributeKvEntries.stream() - .filter(attributeKvEntry -> { - if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() == 0) { - return true; - } - if (entityView.getEndTimeMs() == 0 && entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs()) { - return true; - } - if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs()) { - return true; - } - return entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs() - && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs(); - }).collect(Collectors.toList()); - attributesService.save(entityView.getId(), scope, filteredAttributes); - } - } - - @Override - public void onFailure(Throwable throwable) { - log.error("Failed to fetch [{}] attributes [{}] for [{}] entity [{}]", - scope, keys, entityView.getEntityId().getEntityType().name(), entityView.getEntityId().getId().toString(), throwable); - } - }); - } - } - @Override public EntityView assignEntityViewToCustomer(EntityViewId entityViewId, CustomerId customerId) { EntityView entityView = findEntityViewById(entityViewId); @@ -160,63 +120,66 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti } @Override - public void deleteEntityView(EntityViewId entityViewId) { - log.trace("Executing deleteEntityView [{}]", entityViewId); - Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); + public void unassignCustomerEntityViews(TenantId tenantId, CustomerId customerId) { + log.trace("Executing unassignCustomerEntityViews, tenantId [{}], customerId [{}]", tenantId, customerId); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); + new CustomerEntityViewsUnAssigner(tenantId).removeEntities(customerId); + } + + + @Override + public EntityView findEntityViewById(EntityViewId entityViewId) { + log.trace("Executing findEntityViewById [{}]", entityViewId); validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); - deleteEntityRelations(entityViewId); - EntityView entityView = entityViewDao.findById(entityViewId.getId()); - cache.evict(Arrays.asList(entityView.getTenantId(), entityView.getName())); - entityViewDao.removeById(entityViewId.getId()); + List ids = Arrays.asList(entityViewId.getId()); + Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); + EntityView fromCache = cache.get(ids, EntityView.class); + if (fromCache != null) { + return fromCache; + } else { + ListenableFuture entityViewFuture + = Futures.immediateFuture(entityViewDao.findById(entityViewId.getId())); + Futures.addCallback(entityViewFuture, + new FutureCallback() { + @Override + public void onSuccess(@Nullable EntityView result) { + cache.putIfAbsent(ids, result); + } + @Override + public void onFailure(Throwable t) {} + }); + try { + return entityViewFuture.get(); + } catch (Exception e) { + log.error(e.getMessage()); + } + } + return entityViewDao.findById(entityViewId.getId()); } @Override public TextPageData findEntityViewByTenantId(TenantId tenantId, TextPageLink pageLink) { - log.trace("Executing findEntityViewByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); + log.trace("Executing findEntityViewsByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); - List entityViews = entityViewDao.findEntityViewByTenantId(tenantId.getId(), pageLink); + List entityViews = entityViewDao.findEntityViewsByTenantId(tenantId.getId(), pageLink); return new TextPageData<>(entityViews, pageLink); } - @Override - public void deleteEntityViewsByTenantId(TenantId tenantId) { - log.trace("Executing deleteEntityViewsByTenantId, tenantId [{}]", tenantId); - validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - tenantEntityViewRemover.removeEntities(tenantId); - } - @Override public TextPageData findEntityViewsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink) { - log.trace("Executing findEntityViewByTenantIdAndCustomerId, tenantId [{}], customerId [{}]," + " pageLink [{}]", tenantId, customerId, pageLink); - validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); List entityViews = entityViewDao.findEntityViewsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); - return new TextPageData<>(entityViews, pageLink); } - @Override - public void unassignCustomerEntityViews(TenantId tenantId, CustomerId customerId) { - log.trace("Executing unassignCustomerEntityViews, tenantId [{}], customerId [{}]", tenantId, customerId); - validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); - new CustomerEntityViewsUnAssigner(tenantId).removeEntities(customerId); - } - - @Override - public ListenableFuture findEntityViewByIdAsync(EntityViewId entityViewId) { - log.trace("Executing findEntityViewById [{}]", entityViewId); - validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); - return entityViewDao.findByIdAsync(entityViewId.getId()); - } - @Override public ListenableFuture> findEntityViewsByQuery(EntityViewSearchQuery query) { ListenableFuture> relations = relationService.findByQuery(query.toEntitySearchQuery()); @@ -235,12 +198,99 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti return entityViews; } + @Override + public ListenableFuture findEntityViewByIdAsync(EntityViewId entityViewId) { + log.trace("Executing findEntityViewById [{}]", entityViewId); + validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); + return entityViewDao.findByIdAsync(entityViewId.getId()); + } + @Override public ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId) { log.trace("Executing findEntityViewsByTenantIdAndEntityIdAsync, tenantId [{}], entityId [{}]", tenantId, entityId); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(entityId.getId(), "Incorrect entityId" + entityId); - return entityViewDao.findEntityViewsByTenantIdAndEntityIdAsync(tenantId.getId(), entityId.getId()); + + List tenantAndEntityIds = Arrays.asList(tenantId, entityId); + Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); + List fromCache = cache.get(tenantAndEntityIds, List.class); + if (fromCache != null) { + return Futures.immediateFuture(fromCache); + } else { + ListenableFuture> entityViewsFuture = + entityViewDao.findEntityViewsByTenantIdAndEntityIdAsync(tenantId.getId(), entityId.getId()); + Futures.addCallback(entityViewsFuture, + new FutureCallback>() { + @Override + public void onSuccess(@Nullable List result) { + cache.putIfAbsent(tenantAndEntityIds, result); + } + @Override + public void onFailure(Throwable t) {} + }); + return entityViewsFuture; + } + } + + @Override + public void deleteEntityView(EntityViewId entityViewId) { + log.trace("Executing deleteEntityView [{}]", entityViewId); + validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); + deleteEntityRelations(entityViewId); + cacheEvict(entityViewId, cacheManager.getCache(ENTITY_VIEW_CACHE)); + entityViewDao.removeById(entityViewId.getId()); + } + + @Override + public void deleteEntityViewsByTenantId(TenantId tenantId) { + log.trace("Executing deleteEntityViewsByTenantId, tenantId [{}]", tenantId); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + entityViewDao.findEntityViewsByTenantId(tenantId.getId(), new TextPageLink(DEFAULT_LIMIT)).stream() + .map(view -> view.getId()) + .collect(Collectors.toList()) + .forEach(id -> cacheEvict(id, cacheManager.getCache(ENTITY_VIEW_CACHE))); + tenantEntityViewRemover.removeEntities(tenantId); + } + + private void cacheEvict(EntityViewId entityViewId, Cache cache) { + EntityView entityView = entityViewDao.findById(entityViewId.getId()); + cache.evict(Arrays.asList(entityView.getTenantId(), entityView.getName())); + cache.evict(Arrays.asList(entityView.getTenantId(), entityView.getEntityId())); + } + + private void copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection keys) { + if (keys != null && !keys.isEmpty()) { + ListenableFuture> getAttrFuture = attributesService.find(entityView.getEntityId(), scope, keys); + Futures.addCallback(getAttrFuture, new FutureCallback>() { + @Override + public void onSuccess(@Nullable List attributeKvEntries) { + if (attributeKvEntries != null && !attributeKvEntries.isEmpty()) { + List filteredAttributes = + attributeKvEntries.stream() + .filter(attributeKvEntry -> { + if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() == 0) { + return true; + } + if (entityView.getEndTimeMs() == 0 && entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs()) { + return true; + } + if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs()) { + return true; + } + return entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs() + && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs(); + }).collect(Collectors.toList()); + attributesService.save(entityView.getId(), scope, filteredAttributes); + } + } + + @Override + public void onFailure(Throwable throwable) { + log.error("Failed to fetch [{}] attributes [{}] for [{}] entity [{}]", + scope, keys, entityView.getEntityId().getEntityType().name(), entityView.getEntityId().getId().toString(), throwable); + } + }); + } } private DataValidator entityViewValidator = @@ -296,7 +346,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Override protected List findEntities(TenantId id, TextPageLink pageLink) { - return entityViewDao.findEntityViewByTenantId(id.getId(), pageLink); + return entityViewDao.findEntityViewsByTenantId(id.getId(), pageLink); } @Override 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 0cd1b2b0d6..912c9d5eed 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 @@ -66,7 +66,7 @@ public class JpaEntityViewDao extends JpaAbstractSearchTextDao findEntityViewByTenantId(UUID tenantId, TextPageLink pageLink) { + public List findEntityViewsByTenantId(UUID tenantId, TextPageLink pageLink) { return DaoUtil.convertDataList( entityViewRepository.findByTenantId( fromTimeUUID(tenantId), diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java index d609620edf..c5dcc0f62d 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java @@ -15,9 +15,7 @@ */ package org.thingsboard.rule.engine.action; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.base.Function; -import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.ListenableFuture; import com.google.gson.JsonParser; import lombok.extern.slf4j.Slf4j; @@ -28,24 +26,23 @@ import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.util.DonAsynchron; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.kv.AttributeKvEntry; -import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.session.SessionMsgType; import org.thingsboard.server.common.transport.adaptor.JsonConverter; import javax.annotation.Nullable; -import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; -import static org.thingsboard.rule.engine.api.util.DonAsynchron.withCallback; +import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; @Slf4j @RuleNode( @@ -70,25 +67,22 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException { - if (msg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name()) || - msg.getType().equals(DataConstants.ATTRIBUTES_DELETED) || - msg.getType().equals(DataConstants.ATTRIBUTES_UPDATED)) { + if (!msg.getMetaData().getData().isEmpty()) { long now = System.currentTimeMillis(); - String scope; - if (msg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name())) { - scope = DataConstants.CLIENT_SCOPE; - } else { - scope = msg.getMetaData().getValue("scope"); - } + String scope = msg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name()) ? + DataConstants.CLIENT_SCOPE : msg.getMetaData().getValue("scope"); + ListenableFuture> entityViewsFuture = ctx.getEntityViewService().findEntityViewsByTenantIdAndEntityIdAsync(ctx.getTenantId(), msg.getOriginator()); - withCallback(entityViewsFuture, + + DonAsynchron.withCallback(entityViewsFuture, entityViews -> { - List>> saveFutures = new ArrayList<>(); for (EntityView entityView : entityViews) { - if ((entityView.getEndTimeMs() != 0 && entityView.getEndTimeMs() > now && entityView.getStartTimeMs() < now) || - (entityView.getEndTimeMs() == 0 && entityView.getStartTimeMs() < now)) { - Set attributes = JsonConverter.convertToAttributes(new JsonParser().parse(msg.getData())).getAttributes(); + long startTime = entityView.getStartTimeMs(); + long endTime = entityView.getEndTimeMs(); + if ((endTime != 0 && endTime > now && startTime < now) || (endTime == 0 && startTime < now)) { + Set attributes = + JsonConverter.convertToAttributes(new JsonParser().parse(msg.getData())).getAttributes(); List filteredAttributes = attributes.stream() .filter(attr -> { @@ -110,19 +104,22 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { return entityView.getKeys().getAttributes().getSh().contains(attr.getKey()); } return false; - }) - .collect(Collectors.toList()); - saveFutures.add(ctx.getAttributesService().save(entityView.getId(), scope, new ArrayList<>(filteredAttributes))); + }).collect(Collectors.toList()); + + ctx.getTelemetryService().saveAndNotify(entityView.getId(), scope, filteredAttributes, + new FutureCallback() { + @Override + public void onSuccess(@Nullable Void result) { + ctx.tellNext(msg, SUCCESS); + } + + @Override + public void onFailure(Throwable t) { + ctx.tellFailure(msg, t); + } + }); } } - Futures.transform(Futures.allAsList(saveFutures), new Function>, Object>() { - @Nullable - @Override - public Object apply(@Nullable List> lists) { - ctx.tellNext(msg, TbRelationTypes.SUCCESS); - return null; - } - }); }, t -> ctx.tellFailure(msg, t)); } else { From 7bcb64958dd325e3ac401f57c4ebffb1418cc379 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 26 Sep 2018 11:43:15 +0300 Subject: [PATCH 105/118] Fixed --- .../controller/ControllerSqlTestSuite.java | 2 +- .../dao/entityview/EntityViewServiceImpl.java | 78 ++++++++++--------- 2 files changed, 44 insertions(+), 36 deletions(-) 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 c8a5da8151..a9e94e9184 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.*Test", + "org.thingsboard.server.controller.sql.EntityViewControllerSqlTest", }) public class ControllerSqlTestSuite { 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 79ceff2351..c1c2b6548d 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 @@ -97,10 +97,19 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti log.trace("Executing save entity view [{}]", entityView); entityViewValidator.validate(entityView); EntityView savedEntityView = entityViewDao.save(entityView); + List>> futures = new ArrayList<>(); if (savedEntityView.getKeys() != null) { - copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs()); - copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SERVER_SCOPE, savedEntityView.getKeys().getAttributes().getSs()); - copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SHARED_SCOPE, savedEntityView.getKeys().getAttributes().getSh()); + futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs())); + futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SERVER_SCOPE, savedEntityView.getKeys().getAttributes().getSs())); + futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SHARED_SCOPE, savedEntityView.getKeys().getAttributes().getSh())); + } + for (ListenableFuture> future : futures) { + try { + future.get(); + } catch (InterruptedException | ExecutionException e) { + log.error("Failed to copy attributes to entity view", e); + throw new RuntimeException("Failed to copy attributes to entity view", e); + } } return savedEntityView; } @@ -169,9 +178,9 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Override public TextPageData findEntityViewsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, - TextPageLink pageLink) { + TextPageLink pageLink) { log.trace("Executing findEntityViewByTenantIdAndCustomerId, tenantId [{}], customerId [{}]," + - " pageLink [{}]", tenantId, customerId, pageLink); + " pageLink [{}]", tenantId, customerId, pageLink); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); @@ -246,7 +255,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti log.trace("Executing deleteEntityViewsByTenantId, tenantId [{}]", tenantId); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); entityViewDao.findEntityViewsByTenantId(tenantId.getId(), new TextPageLink(DEFAULT_LIMIT)).stream() - .map(view -> view.getId()) + .map(view -> view.getId()) .collect(Collectors.toList()) .forEach(id -> cacheEvict(id, cacheManager.getCache(ENTITY_VIEW_CACHE))); tenantEntityViewRemover.removeEntities(tenantId); @@ -258,38 +267,37 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti cache.evict(Arrays.asList(entityView.getTenantId(), entityView.getEntityId())); } - private void copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection keys) { + private ListenableFuture> copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection keys) { if (keys != null && !keys.isEmpty()) { ListenableFuture> getAttrFuture = attributesService.find(entityView.getEntityId(), scope, keys); - Futures.addCallback(getAttrFuture, new FutureCallback>() { - @Override - public void onSuccess(@Nullable List attributeKvEntries) { - if (attributeKvEntries != null && !attributeKvEntries.isEmpty()) { - List filteredAttributes = - attributeKvEntries.stream() - .filter(attributeKvEntry -> { - if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() == 0) { - return true; - } - if (entityView.getEndTimeMs() == 0 && entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs()) { - return true; - } - if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs()) { - return true; - } - return entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs() - && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs(); - }).collect(Collectors.toList()); - attributesService.save(entityView.getId(), scope, filteredAttributes); - } + return Futures.transform(getAttrFuture, attributeKvEntries -> { + List filteredAttributes = new ArrayList<>(); + if (attributeKvEntries != null && !attributeKvEntries.isEmpty()) { + filteredAttributes = + attributeKvEntries.stream() + .filter(attributeKvEntry -> { + if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() == 0) { + return true; + } + if (entityView.getEndTimeMs() == 0 && entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs()) { + return true; + } + if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs()) { + return true; + } + return entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs() + && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs(); + }).collect(Collectors.toList()); } - - @Override - public void onFailure(Throwable throwable) { - log.error("Failed to fetch [{}] attributes [{}] for [{}] entity [{}]", - scope, keys, entityView.getEntityId().getEntityType().name(), entityView.getEntityId().getId().toString(), throwable); + try { + return attributesService.save(entityView.getId(), scope, filteredAttributes).get(); + } catch (InterruptedException | ExecutionException e) { + log.error("Failed to copy attributes to entity view", e); + throw new RuntimeException("Failed to copy attributes to entity view", e); } }); + } else { + return Futures.immediateFuture(null); } } @@ -299,7 +307,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Override protected void validateCreate(EntityView entityView) { entityViewDao.findEntityViewByTenantIdAndName(entityView.getTenantId().getId(), entityView.getName()) - .ifPresent( e -> { + .ifPresent(e -> { throw new DataValidationException("Entity view with such name already exists!"); }); } @@ -307,7 +315,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Override protected void validateUpdate(EntityView entityView) { entityViewDao.findEntityViewByTenantIdAndName(entityView.getTenantId().getId(), entityView.getName()) - .ifPresent( e -> { + .ifPresent(e -> { if (!e.getUuidId().equals(entityView.getUuidId())) { throw new DataValidationException("Entity view with such name already exists!"); } From 87eb21d68ff41ea15a27a9b28714e79173bb71d8 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Thu, 27 Sep 2018 13:11:06 +0300 Subject: [PATCH 106/118] Were fixed caches --- .../dao/entityview/EntityViewServiceImpl.java | 76 ++++--------------- 1 file changed, 14 insertions(+), 62 deletions(-) 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 c1c2b6548d..a45a6419b1 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,7 +15,6 @@ */ package org.thingsboard.server.dao.entityview; -import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; @@ -24,6 +23,8 @@ 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.cache.annotation.Caching; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.DataConstants; @@ -40,7 +41,6 @@ import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; -import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.customer.CustomerDao; import org.thingsboard.server.dao.entity.AbstractEntityService; @@ -49,12 +49,10 @@ 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.Arrays; import java.util.Collection; import java.util.List; -import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; @@ -74,7 +72,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti public static final String INCORRECT_PAGE_LINK = "Incorrect page link "; public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId "; public static final String INCORRECT_ENTITY_VIEW_ID = "Incorrect entityViewId "; - private static final int DEFAULT_LIMIT = 100; @Autowired private EntityViewDao entityViewDao; @@ -91,12 +88,15 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Autowired private CacheManager cacheManager; - @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityView.tenantId, #entityView.name}") + @Caching(evict = { + @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityView.tenantId, #entityView.entityId}"), + @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityView.id}")}) @Override public EntityView saveEntityView(EntityView entityView) { log.trace("Executing save entity view [{}]", entityView); entityViewValidator.validate(entityView); EntityView savedEntityView = entityViewDao.save(entityView); + List>> futures = new ArrayList<>(); if (savedEntityView.getKeys() != null) { futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs())); @@ -121,6 +121,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti return saveEntityView(entityView); } + @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}") @Override public EntityView unassignEntityViewFromCustomer(EntityViewId entityViewId) { EntityView entityView = findEntityViewById(entityViewId); @@ -136,34 +137,11 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti new CustomerEntityViewsUnAssigner(tenantId).removeEntities(customerId); } - + @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}") @Override public EntityView findEntityViewById(EntityViewId entityViewId) { log.trace("Executing findEntityViewById [{}]", entityViewId); validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); - List ids = Arrays.asList(entityViewId.getId()); - Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); - EntityView fromCache = cache.get(ids, EntityView.class); - if (fromCache != null) { - return fromCache; - } else { - ListenableFuture entityViewFuture - = Futures.immediateFuture(entityViewDao.findById(entityViewId.getId())); - Futures.addCallback(entityViewFuture, - new FutureCallback() { - @Override - public void onSuccess(@Nullable EntityView result) { - cache.putIfAbsent(ids, result); - } - @Override - public void onFailure(Throwable t) {} - }); - try { - return entityViewFuture.get(); - } catch (Exception e) { - log.error(e.getMessage()); - } - } return entityViewDao.findById(entityViewId.getId()); } @@ -203,7 +181,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti } return Futures.successfulAsList(futures); }); - return entityViews; } @@ -214,39 +191,24 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti return entityViewDao.findByIdAsync(entityViewId.getId()); } + @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #entityId}") @Override public ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId) { log.trace("Executing findEntityViewsByTenantIdAndEntityIdAsync, tenantId [{}], entityId [{}]", tenantId, entityId); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(entityId.getId(), "Incorrect entityId" + entityId); - - List tenantAndEntityIds = Arrays.asList(tenantId, entityId); - Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); - List fromCache = cache.get(tenantAndEntityIds, List.class); - if (fromCache != null) { - return Futures.immediateFuture(fromCache); - } else { - ListenableFuture> entityViewsFuture = - entityViewDao.findEntityViewsByTenantIdAndEntityIdAsync(tenantId.getId(), entityId.getId()); - Futures.addCallback(entityViewsFuture, - new FutureCallback>() { - @Override - public void onSuccess(@Nullable List result) { - cache.putIfAbsent(tenantAndEntityIds, result); - } - @Override - public void onFailure(Throwable t) {} - }); - return entityViewsFuture; - } + return entityViewDao.findEntityViewsByTenantIdAndEntityIdAsync(tenantId.getId(), entityId.getId()); } + @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}") @Override public void deleteEntityView(EntityViewId entityViewId) { log.trace("Executing deleteEntityView [{}]", entityViewId); validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); deleteEntityRelations(entityViewId); - cacheEvict(entityViewId, cacheManager.getCache(ENTITY_VIEW_CACHE)); + Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); + EntityView entityView = entityViewDao.findById(entityViewId.getId()); + cache.evict(Arrays.asList(entityView.getTenantId(), entityView.getEntityId())); entityViewDao.removeById(entityViewId.getId()); } @@ -254,19 +216,9 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti public void deleteEntityViewsByTenantId(TenantId tenantId) { log.trace("Executing deleteEntityViewsByTenantId, tenantId [{}]", tenantId); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - entityViewDao.findEntityViewsByTenantId(tenantId.getId(), new TextPageLink(DEFAULT_LIMIT)).stream() - .map(view -> view.getId()) - .collect(Collectors.toList()) - .forEach(id -> cacheEvict(id, cacheManager.getCache(ENTITY_VIEW_CACHE))); tenantEntityViewRemover.removeEntities(tenantId); } - private void cacheEvict(EntityViewId entityViewId, Cache cache) { - EntityView entityView = entityViewDao.findById(entityViewId.getId()); - cache.evict(Arrays.asList(entityView.getTenantId(), entityView.getName())); - cache.evict(Arrays.asList(entityView.getTenantId(), entityView.getEntityId())); - } - private ListenableFuture> copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection keys) { if (keys != null && !keys.isEmpty()) { ListenableFuture> getAttrFuture = attributesService.find(entityView.getEntityId(), scope, keys); From 5a65ec75fe6dece007277555044770ed8952efd4 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Thu, 27 Sep 2018 17:07:54 +0300 Subject: [PATCH 107/118] Reviewed --- .../dao/entityview/EntityViewServiceImpl.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) 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 a45a6419b1..9fdadcd631 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 @@ -228,17 +228,13 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti filteredAttributes = attributeKvEntries.stream() .filter(attributeKvEntry -> { - if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() == 0) { - return true; - } - if (entityView.getEndTimeMs() == 0 && entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs()) { - return true; - } - if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs()) { - return true; - } - return entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs() - && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs(); + long startTime = entityView.getStartTimeMs(); + long endTime = entityView.getEndTimeMs(); + long lastUpdateTs = attributeKvEntry.getLastUpdateTs(); + return startTime == 0 && endTime == 0 || + (endTime == 0 && startTime < lastUpdateTs) || + (startTime == 0 && endTime > lastUpdateTs) || + (startTime < lastUpdateTs && endTime > lastUpdateTs); }).collect(Collectors.toList()); } try { From 49a98673525407ace293bc86a14b2a44a2a88fbe Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Fri, 28 Sep 2018 17:56:32 +0300 Subject: [PATCH 108/118] After review --- .../BaseEntityViewControllerTest.java | 86 +++++++++++++------ .../dao/entityview/EntityViewServiceImpl.java | 4 +- 2 files changed, 64 insertions(+), 26 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index 0daaeca72f..a877cbf71a 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -319,12 +319,62 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes } @Test - public void testTheCopyOfAttrsThatMatchWithDeviceCriteriaForTheView() throws Exception { + public void testTheCopyOfAttrsIntoTSForTheView() throws Exception { + Set actualAttributesSet = + getAttributesByKeys("{\"caValue1\":\"value1\", \"caValue2\":true, \"caValue3\":42.0, \"caValue4\":73}"); - String viewDeviceId = testDevice.getId().getId().toString(); - DeviceCredentials deviceCredentials - = doGet("/api/device/" + viewDeviceId + "/credentials", DeviceCredentials.class); + Set expectedActualAttributesSet = + new HashSet<>(Arrays.asList("caValue1", "caValue2", "caValue3", "caValue4")); + assertTrue(actualAttributesSet.containsAll(expectedActualAttributesSet)); + Thread.sleep(1000); + + EntityView savedView = getNewSavedEntityView("Test entity view"); + String urlOfTelemetryValues = "/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + + "/values/attributes?keys=" + String.join(",", actualAttributesSet); + List> values = doGetAsync(urlOfTelemetryValues, List.class); + + assertEquals("value1", getValue(values, "caValue1")); + assertEquals(true, getValue(values, "caValue2")); + assertEquals(42.0, getValue(values, "caValue3")); + assertEquals(73, getValue(values, "caValue4")); + } + + @Test + public void testTheCopyOfAttrsOutOfTSForTheView() throws Exception { + Set actualAttributesSet = + getAttributesByKeys("{\"caValue1\":\"value1\", \"caValue2\":true, \"caValue3\":42.0, \"caValue4\":73}"); + + Set expectedActualAttributesSet = new HashSet<>(Arrays.asList("caValue1", "caValue2", "caValue3", "caValue4")); + assertTrue(actualAttributesSet.containsAll(expectedActualAttributesSet)); + Thread.sleep(1000); + + List> values = doGetAsync("/api/plugins/telemetry/DEVICE/" + testDevice.getId().getId().toString() + + "/values/attributes?keys=" + String.join(",", actualAttributesSet), List.class); + + EntityView view = new EntityView(); + view.setEntityId(testDevice.getId()); + view.setTenantId(savedTenant.getId()); + view.setName("Test entity view"); + view.setKeys(telemetry); + view.setStartTimeMs((long) getValue(values, "lastUpdateTs") * 10); + view.setEndTimeMs((long) getValue(values, "lastUpdateTs") / 10); + EntityView savedView = doPost("/api/entityView", view, EntityView.class); + + String urlOfTelemetryValues = "/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + + "/values/attributes?keys=" + String.join(",", actualAttributesSet); + values = doGetAsync(urlOfTelemetryValues, List.class); + + assertEquals("value1", getValue(values, "caValue1")); + assertEquals(true, getValue(values, "caValue2")); + assertEquals(42.0, getValue(values, "caValue3")); + assertEquals(73, getValue(values, "caValue4")); + } + + private Set getAttributesByKeys(String stringKV) throws Exception { + String viewDeviceId = testDevice.getId().getId().toString(); + DeviceCredentials deviceCredentials = + doGet("/api/device/" + viewDeviceId + "/credentials", DeviceCredentials.class); assertEquals(testDevice.getId(), deviceCredentials.getDeviceId()); String accessToken = deviceCredentials.getCredentialsId(); @@ -339,31 +389,19 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes Thread.sleep(3000); MqttMessage message = new MqttMessage(); - message.setPayload(("{\"caValue1\":\"value1\", \"caValue2\":true, \"caValue3\":42.0, \"caValue4\":73}").getBytes()); + message.setPayload((stringKV).getBytes()); client.publish("v1/devices/me/attributes", message); Thread.sleep(1000); - List actualAttributes = - doGetAsync("/api/plugins/telemetry/DEVICE/" + viewDeviceId + "/keys/attributes", List.class); - Set actualAttributesSet = new HashSet<>(actualAttributes); - - List expectedActualAttributes = Arrays.asList("caValue1", "caValue2", "caValue3", "caValue4"); - Set expectedActualAttributesSet = new HashSet<>(expectedActualAttributes); - assertTrue(actualAttributesSet.containsAll(expectedActualAttributesSet)); - Thread.sleep(1000); - - EntityView savedView = getNewSavedEntityView("Test entity view"); - String urlOfTelemetryValues = "/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + - "/values/attributes?keys=" + String.join(",", actualAttributesSet); - List> values = doGetAsync(urlOfTelemetryValues, List.class); - - assertEquals("value1", getValueOfMap(values, "caValue1")); - assertEquals(true, getValueOfMap(values, "caValue2")); - assertEquals(42.0, getValueOfMap(values, "caValue3")); - assertEquals(73, getValueOfMap(values, "caValue4")); + return new HashSet<>(doGetAsync("/api/plugins/telemetry/DEVICE/" + viewDeviceId + "/keys/attributes", List.class)); } - private Object getValueOfMap(List> values, String stringValue) { + /*private Object getLastTs(List> values) { + return values.stream() + .filter(value -> value.get("key"); + } +*/ + private Object getValue(List> values, String stringValue) { return values.stream() .filter(value -> value.get("key").equals(stringValue)) .findFirst().get().get("value"); 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 9fdadcd631..6e7eba08c8 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 @@ -233,8 +233,8 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti long lastUpdateTs = attributeKvEntry.getLastUpdateTs(); return startTime == 0 && endTime == 0 || (endTime == 0 && startTime < lastUpdateTs) || - (startTime == 0 && endTime > lastUpdateTs) || - (startTime < lastUpdateTs && endTime > lastUpdateTs); + (startTime == 0 && endTime > lastUpdateTs) + ? true : startTime < lastUpdateTs && endTime > lastUpdateTs; }).collect(Collectors.toList()); } try { From d32a36c312611e48a762821f9551eb8d186f4a45 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Fri, 28 Sep 2018 20:11:45 +0300 Subject: [PATCH 109/118] added test --- .../BaseEntityViewControllerTest.java | 36 +++++++------------ 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index a877cbf71a..ee97b97fa0 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -50,6 +50,7 @@ import java.util.Set; import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; @@ -329,9 +330,8 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes Thread.sleep(1000); EntityView savedView = getNewSavedEntityView("Test entity view"); - String urlOfTelemetryValues = "/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + - "/values/attributes?keys=" + String.join(",", actualAttributesSet); - List> values = doGetAsync(urlOfTelemetryValues, List.class); + List> values = doGetAsync("/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + + "/values/attributes?keys=" + String.join(",", actualAttributesSet), List.class); assertEquals("value1", getValue(values, "caValue1")); assertEquals(true, getValue(values, "caValue2")); @@ -348,7 +348,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes assertTrue(actualAttributesSet.containsAll(expectedActualAttributesSet)); Thread.sleep(1000); - List> values = doGetAsync("/api/plugins/telemetry/DEVICE/" + testDevice.getId().getId().toString() + + List> valueTelemetryOfDevices = doGetAsync("/api/plugins/telemetry/DEVICE/" + testDevice.getId().getId().toString() + "/values/attributes?keys=" + String.join(",", actualAttributesSet), List.class); EntityView view = new EntityView(); @@ -356,19 +356,13 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes view.setTenantId(savedTenant.getId()); view.setName("Test entity view"); view.setKeys(telemetry); - view.setStartTimeMs((long) getValue(values, "lastUpdateTs") * 10); - view.setEndTimeMs((long) getValue(values, "lastUpdateTs") / 10); + view.setStartTimeMs((long) getValue(valueTelemetryOfDevices, "lastActivityTime") * 10); + view.setEndTimeMs((long) getValue(valueTelemetryOfDevices, "lastActivityTime") / 10); EntityView savedView = doPost("/api/entityView", view, EntityView.class); - String urlOfTelemetryValues = "/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + - "/values/attributes?keys=" + String.join(",", actualAttributesSet); - values = doGetAsync(urlOfTelemetryValues, List.class); - - - assertEquals("value1", getValue(values, "caValue1")); - assertEquals(true, getValue(values, "caValue2")); - assertEquals(42.0, getValue(values, "caValue3")); - assertEquals(73, getValue(values, "caValue4")); + List> values = doGetAsync("/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + + "/values/attributes?keys=" + String.join(",", actualAttributesSet), List.class); + assertEquals(0, values.size()); } private Set getAttributesByKeys(String stringKV) throws Exception { @@ -396,15 +390,11 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes return new HashSet<>(doGetAsync("/api/plugins/telemetry/DEVICE/" + viewDeviceId + "/keys/attributes", List.class)); } - /*private Object getLastTs(List> values) { - return values.stream() - .filter(value -> value.get("key"); - } -*/ private Object getValue(List> values, String stringValue) { - return values.stream() - .filter(value -> value.get("key").equals(stringValue)) - .findFirst().get().get("value"); + return values.size() == 0 ? null : + values.stream() + .filter(value -> value.get("key").equals(stringValue)) + .findFirst().get().get("value"); } private EntityView getNewSavedEntityView(String name) throws Exception { From 48bae4b2b421e4fd0ffd5a1a98fb572d415bcdc6 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Sat, 29 Sep 2018 11:30:07 +0300 Subject: [PATCH 110/118] Code review fixes --- .../server/controller/BaseController.java | 6 ++-- .../controller/EntityViewController.java | 2 +- .../controller/ControllerSqlTestSuite.java | 2 +- .../dao/entityview/EntityViewServiceImpl.java | 31 +++++++++++++++++-- .../TbCopyAttributesToEntityViewNode.java | 11 ++++--- 5 files changed, 40 insertions(+), 12 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 84a8151316..af62e04cff 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -318,7 +318,7 @@ public abstract class BaseController { checkUserId(new UserId(entityId.getId())); return; case ENTITY_VIEW: - checkEntityViewId(entityViewService.findEntityViewById(new EntityViewId(entityId.getId()))); + checkEntityView(entityViewService.findEntityViewById(new EntityViewId(entityId.getId()))); return; default: throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType()); @@ -351,14 +351,14 @@ public abstract class BaseController { try { validateId(entityViewId, "Incorrect entityViewId " + entityViewId); EntityView entityView = entityViewService.findEntityViewById(entityViewId); - checkEntityViewId(entityView); + checkEntityView(entityView); return entityView; } catch (Exception e) { throw handleException(e, false); } } - protected void checkEntityViewId(EntityView entityView) throws ThingsboardException { + protected void checkEntityView(EntityView entityView) throws ThingsboardException { checkNotNull(entityView); checkTenantId(entityView.getTenantId()); if (entityView.getCustomerId() != null && !entityView.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { 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 e6f149e05c..0ba35e85ad 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java @@ -204,7 +204,7 @@ public class EntityViewController extends BaseController { List entityViews = checkNotNull(entityViewService.findEntityViewsByQuery(query).get()); entityViews = entityViews.stream().filter(entityView -> { try { - checkEntityViewId(entityView); + checkEntityView(entityView); return true; } catch (ThingsboardException e) { return false; 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 a9e94e9184..c8a5da8151 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/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index 6e7eba08c8..29ee9e46a0 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,6 +15,7 @@ */ package org.thingsboard.server.dao.entityview; +import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; @@ -49,6 +50,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.Arrays; import java.util.Collection; @@ -57,6 +59,7 @@ import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import static org.thingsboard.server.common.data.CacheConstants.ENTITY_VIEW_CACHE; +import static org.thingsboard.server.common.data.CacheConstants.RELATIONS_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; @@ -197,7 +200,30 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti log.trace("Executing findEntityViewsByTenantIdAndEntityIdAsync, tenantId [{}], entityId [{}]", tenantId, entityId); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(entityId.getId(), "Incorrect entityId" + entityId); - return entityViewDao.findEntityViewsByTenantIdAndEntityIdAsync(tenantId.getId(), entityId.getId()); + + List tenantIdAndEntityId = new ArrayList<>(); + tenantIdAndEntityId.add(tenantId); + tenantIdAndEntityId.add(entityId); + + Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); + List fromCache = cache.get(tenantIdAndEntityId, List.class); + if (fromCache != null) { + return Futures.immediateFuture(fromCache); + } else { + ListenableFuture> entityViewsFuture = entityViewDao.findEntityViewsByTenantIdAndEntityIdAsync(tenantId.getId(), entityId.getId()); + Futures.addCallback(entityViewsFuture, + new FutureCallback>() { + @Override + public void onSuccess(@Nullable List result) { + cache.putIfAbsent(tenantIdAndEntityId, result); + } + @Override + public void onFailure(Throwable t) { + log.error("Error while finding entity views by tenantId and entityId", t); + } + }); + return entityViewsFuture; + } } @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}") @@ -206,9 +232,8 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti log.trace("Executing deleteEntityView [{}]", entityViewId); validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); deleteEntityRelations(entityViewId); - Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); EntityView entityView = entityViewDao.findById(entityViewId.getId()); - cache.evict(Arrays.asList(entityView.getTenantId(), entityView.getEntityId())); + cacheManager.getCache(ENTITY_VIEW_CACHE).evict(Arrays.asList(entityView.getTenantId(), entityView.getEntityId())); entityViewDao.removeById(entityViewId.getId()); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java index c5dcc0f62d..40e00ec009 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java @@ -42,6 +42,7 @@ import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; +import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE; import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; @Slf4j @@ -49,9 +50,10 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; type = ComponentType.ACTION, name = "copy attributes", configClazz = EmptyNodeConfiguration.class, - nodeDescription = "Copy attributes from asset/device to entity view", + nodeDescription = "Copy attributes from asset/device to entity view and changes message originator to related entity view", nodeDetails = "Copy attributes from asset/device to related entity view according to entity view configuration. \n " + - "Copy will be done only for attributes that are between start and end dates and according to attribute keys configuration", + "Copy will be done only for attributes that are between start and end dates and according to attribute keys configuration. \n" + + "Changes message originator to related entity view and produces new messages according to count of updated entity views", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbNodeEmptyConfig", icon = "content_copy" @@ -110,7 +112,8 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { new FutureCallback() { @Override public void onSuccess(@Nullable Void result) { - ctx.tellNext(msg, SUCCESS); + TbMsg updMsg = ctx.transformMsg(msg, msg.getType(), entityView.getId(), msg.getMetaData(), msg.getData()); + ctx.tellNext(updMsg, SUCCESS); } @Override @@ -123,7 +126,7 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { }, t -> ctx.tellFailure(msg, t)); } else { - ctx.tellNext(msg, TbRelationTypes.FAILURE); + ctx.tellNext(msg, FAILURE); } } From 0b5f61338ee7395727740ee460b50196b2646c0c Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Sat, 29 Sep 2018 11:32:02 +0300 Subject: [PATCH 111/118] Code review fixes --- .../java/org/thingsboard/server/controller/BaseController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index af62e04cff..889630b81f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -318,7 +318,7 @@ public abstract class BaseController { checkUserId(new UserId(entityId.getId())); return; case ENTITY_VIEW: - checkEntityView(entityViewService.findEntityViewById(new EntityViewId(entityId.getId()))); + checkEntityViewId(new EntityViewId(entityId.getId())); return; default: throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType()); From 80f0d1eb8a5f018e75ed9db6a58ed3f3728545b6 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Sat, 29 Sep 2018 11:33:24 +0300 Subject: [PATCH 112/118] Code review fixes --- .../thingsboard/server/dao/entityview/EntityViewServiceImpl.java | 1 - 1 file changed, 1 deletion(-) 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 29ee9e46a0..2c5ec75485 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 @@ -194,7 +194,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti return entityViewDao.findByIdAsync(entityViewId.getId()); } - @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #entityId}") @Override public ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId) { log.trace("Executing findEntityViewsByTenantIdAndEntityIdAsync, tenantId [{}], entityId [{}]", tenantId, entityId); From 02895bf31ddc9a389772f3f6b5ebfe5ea2815454 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Sat, 29 Sep 2018 22:09:18 +0300 Subject: [PATCH 113/118] Typo fixed --- application/src/main/resources/thingsboard.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 4d89eafcab..0f5a7fb21b 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -160,9 +160,9 @@ quota: database: entities: - type: "${DATABASE_TS_TYPE:sql}" # cassandra OR sql + type: "${DATABASE_ENTITIES_TYPE:sql}" # cassandra OR sql ts: - type: "${DATABASE_CASSANDRA_TYPE:sql}" # cassandra OR sql (for hybrid mode, only this value should be cassandra) + type: "${DATABASE_TS_TYPE:sql}" # cassandra OR sql (for hybrid mode, only this value should be cassandra) # Cassandra driver configuration parameters From ca62616cccc77feccd69eb7c3526437b112dd11d Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 3 Oct 2018 11:26:36 +0300 Subject: [PATCH 114/118] Fixes for cases when asset/device deleted but has entity view assigned --- .../server/dao/asset/BaseAssetService.java | 17 +++++++++++++- .../server/dao/device/DeviceServiceImpl.java | 22 +++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) 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 6c8b60914e..f35b89069c 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 @@ -30,6 +30,7 @@ import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.AssetSearchQuery; @@ -43,6 +44,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.dao.customer.CustomerDao; import org.thingsboard.server.dao.entity.AbstractEntityService; +import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; @@ -76,6 +78,9 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ @Autowired private CustomerDao customerDao; + @Autowired + private EntityViewService entityViewService; + @Autowired private CacheManager cacheManager; @@ -130,11 +135,21 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ validateId(assetId, INCORRECT_ASSET_ID + assetId); deleteEntityRelations(assetId); - Cache cache = cacheManager.getCache(ASSET_CACHE); Asset asset = assetDao.findById(assetId.getId()); + try { + List entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(asset.getTenantId(), assetId).get(); + if (entityViews != null && !entityViews.isEmpty()) { + throw new DataValidationException("Can't delete asset that is assigned to entity views!"); + } + } catch (Exception e) { + log.error("Exception while finding entity views for assetId [{}]", assetId, e); + throw new RuntimeException("Exception while finding entity views for assetId [" + assetId + "]", e); + } + List list = new ArrayList<>(); list.add(asset.getTenantId()); list.add(asset.getName()); + Cache cache = cacheManager.getCache(ASSET_CACHE); cache.evict(list); assetDao.removeById(assetId.getId()); 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 3930e3a94f..44af6e0363 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 @@ -31,6 +31,7 @@ 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.device.DeviceSearchQuery; import org.thingsboard.server.common.data.id.CustomerId; @@ -45,6 +46,7 @@ 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.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; @@ -86,6 +88,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @Autowired private DeviceCredentialsService deviceCredentialsService; + @Autowired + private EntityViewService entityViewService; + @Autowired private CacheManager cacheManager; @@ -145,18 +150,31 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @Override public void deleteDevice(DeviceId deviceId) { log.trace("Executing deleteDevice [{}]", deviceId); - Cache cache = cacheManager.getCache(DEVICE_CACHE); validateId(deviceId, INCORRECT_DEVICE_ID + deviceId); + + Device device = deviceDao.findById(deviceId.getId()); + try { + List entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(device.getTenantId(), deviceId).get(); + if (entityViews != null && !entityViews.isEmpty()) { + throw new DataValidationException("Can't delete device that is assigned to entity views!"); + } + } catch (Exception e) { + log.error("Exception while finding entity views for deviceId [{}]", deviceId, e); + throw new RuntimeException("Exception while finding entity views for deviceId [" + deviceId + "]", e); + } + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(deviceId); if (deviceCredentials != null) { deviceCredentialsService.deleteDeviceCredentials(deviceCredentials); } deleteEntityRelations(deviceId); - Device device = deviceDao.findById(deviceId.getId()); + List list = new ArrayList<>(); list.add(device.getTenantId()); list.add(device.getName()); + Cache cache = cacheManager.getCache(DEVICE_CACHE); cache.evict(list); + deviceDao.removeById(deviceId.getId()); } From 78b40b097a8fc1ab93eef3007424b3e1e3ca4efa Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 3 Oct 2018 12:42:28 +0300 Subject: [PATCH 115/118] Fixes for cases when asset/device deleted but has entity view assigned --- dao/src/test/resources/application-test.properties | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dao/src/test/resources/application-test.properties b/dao/src/test/resources/application-test.properties index 20cf91c3dd..a61c285136 100644 --- a/dao/src/test/resources/application-test.properties +++ b/dao/src/test/resources/application-test.properties @@ -24,6 +24,9 @@ caffeine.specs.devices.maxSize=100000 caffeine.specs.assets.timeToLiveInMinutes=1440 caffeine.specs.assets.maxSize=100000 +caffeine.specs.entityViews.timeToLiveInMinutes=1440 +caffeine.specs.entityViews.maxSize=100000 + caching.specs.devices.timeToLiveInMinutes=1440 caching.specs.devices.maxSize=100000 From 321d4f1cb2680a2335aa24b0b2b4353e998ecbf8 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 3 Oct 2018 13:08:50 +0300 Subject: [PATCH 116/118] Fixes for cases when asset/device deleted but has entity view assigned --- .../server/dao/entityview/CassandraEntityViewDao.java | 9 +++++---- .../thingsboard/server/dao/model/ModelConstants.java | 3 ++- dao/src/main/resources/cassandra/schema-entities.cql | 11 +++++++++++ 3 files changed, 18 insertions(+), 5 deletions(-) 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 395f9022b0..a2e049bfe8 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 @@ -40,7 +40,8 @@ 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.CUSTOMER_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_ID_COLUMN; -import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_SEARCH_TEXT; +import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_CF; +import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_BY_TENANT_AND_ENTITY_ID_CF; import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_BY_TENANT_AND_NAME; import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME; import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_NAME_PROPERTY; @@ -101,7 +102,7 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao entityViewEntities = findPageWithTextSearch( - ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_SEARCH_TEXT, + 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 [{}]", @@ -112,9 +113,9 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao> findEntityViewsByTenantIdAndEntityIdAsync(UUID tenantId, UUID entityId) { log.debug("Try to find entity views by tenantId [{}] and entityId [{}]", tenantId, entityId); - Select.Where query = select().from(getColumnFamilyName()).where(); + Select.Where query = select().from(ENTITY_VIEW_BY_TENANT_AND_ENTITY_ID_CF).where(); query.and(eq(TENANT_ID_PROPERTY, tenantId)); - query.and(eq(ENTITY_ID_COLUMN, entityId)); + query.and(eq(ENTITY_ID_COLUMN, entityId));dr return findListByStatementAsync(query); } } 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 9890ff62d3..a487ede93a 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 @@ -150,7 +150,8 @@ 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_BY_TENANT_AND_CUSTOMER_AND_SEARCH_TEXT = "entity_view_by_tenant_and_customer"; + 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_ENTITY_ID_CF = "entity_view_by_tenant_and_entity_id"; public static final String ENTITY_VIEW_KEYS_PROPERTY = "keys"; public static final String ENTITY_VIEW_START_TS_PROPERTY = "start_ts"; public static final String ENTITY_VIEW_END_TS_PROPERTY = "end_ts"; diff --git a/dao/src/main/resources/cassandra/schema-entities.cql b/dao/src/main/resources/cassandra/schema-entities.cql index bd978f7960..7ccd41f03a 100644 --- a/dao/src/main/resources/cassandra/schema-entities.cql +++ b/dao/src/main/resources/cassandra/schema-entities.cql @@ -671,3 +671,14 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_cus AND id IS NOT NULL PRIMARY KEY (tenant_id, customer_id, search_text, id, entity_id) WITH CLUSTERING ORDER BY (customer_id DESC, search_text ASC, id DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_entity_id AS + SELECT * + from thingsboard.entity_views + WHERE tenant_id IS NOT NULL + AND customer_id IS NOT NULL + AND entity_id IS NOT NULL + AND search_text IS NOT NULL + AND id IS NOT NULL + PRIMARY KEY (tenant_id, entity_id, customer_id, search_text, id) + WITH CLUSTERING ORDER BY (entity_id DESC, customer_id DESC, search_text ASC, id DESC); \ No newline at end of file From b1f9ffb3b8ee1307ace49fa2919922f5c47a7b1a Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 3 Oct 2018 13:12:23 +0300 Subject: [PATCH 117/118] Fixes for cases when asset/device deleted but has entity view assigned --- .../src/main/data/upgrade/2.1.1/schema_update.cql | 11 +++++++++++ .../server/dao/entityview/CassandraEntityViewDao.java | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) 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 a633634f60..46a47d551f 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 @@ -67,3 +67,14 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_cus AND id IS NOT NULL PRIMARY KEY (tenant_id, customer_id, search_text, id, entity_id) WITH CLUSTERING ORDER BY (customer_id DESC, search_text ASC, id DESC); + +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_entity_id AS + SELECT * + from thingsboard.entity_views + WHERE tenant_id IS NOT NULL + AND customer_id IS NOT NULL + AND entity_id IS NOT NULL + AND search_text IS NOT NULL + AND id IS NOT NULL + PRIMARY KEY (tenant_id, entity_id, customer_id, search_text, id) + WITH CLUSTERING ORDER BY (entity_id DESC, customer_id DESC, search_text ASC, id DESC); \ No newline at end of file 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 a2e049bfe8..a03dd89815 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 @@ -115,7 +115,7 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao Date: Wed, 3 Oct 2018 17:43:29 +0300 Subject: [PATCH 118/118] Fixes for cases when asset/device deleted but has entity view assigned --- application/src/main/data/upgrade/2.1.1/schema_update.cql | 3 ++- .../thingsboard/server/dao/customer/CustomerServiceImpl.java | 2 +- .../org/thingsboard/server/dao/device/DeviceServiceImpl.java | 4 ++-- .../org/thingsboard/server/dao/tenant/TenantServiceImpl.java | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) 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 46a47d551f..c477e8a02a 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 @@ -17,9 +17,10 @@ DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_name; DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_search_text; DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_customer; +DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_entity_id; DROP TABLE IF EXISTS thingsboard.entity_views; - +ControllerSqlTestSuite CREATE TABLE IF NOT EXISTS thingsboard.entity_views ( id timeuuid, entity_id timeuuid, diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java index 9d96f3a97a..a9b8bfe181 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java @@ -115,9 +115,9 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom throw new IncorrectParameterException("Unable to delete non-existent customer."); } dashboardService.unassignCustomerDashboards(customerId); + entityViewService.unassignCustomerEntityViews(customer.getTenantId(), customerId); assetService.unassignCustomerAssets(customer.getTenantId(), customerId); deviceService.unassignCustomerDevices(customer.getTenantId(), customerId); - entityViewService.unassignCustomerEntityViews(customer.getTenantId(), customerId); userService.deleteCustomerUsers(customer.getTenantId(), customerId); deleteEntityRelations(customerId); customerDao.removeById(customerId.getId()); 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 44af6e0363..6f9ea62244 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 @@ -155,8 +155,8 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe Device device = deviceDao.findById(deviceId.getId()); try { List entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(device.getTenantId(), deviceId).get(); - if (entityViews != null && !entityViews.isEmpty()) { - throw new DataValidationException("Can't delete device that is assigned to entity views!"); + if (entityViews != null && !entityViews.isEmpty()) { + throw new DataValidationException("Can't delete device that is assigned to entity views!"); } } catch (Exception e) { log.error("Exception while finding entity views for deviceId [{}]", deviceId, e); diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index a94e715616..189c7139ac 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -105,9 +105,9 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe customerService.deleteCustomersByTenantId(tenantId); widgetsBundleService.deleteWidgetsBundlesByTenantId(tenantId); dashboardService.deleteDashboardsByTenantId(tenantId); + entityViewService.deleteEntityViewsByTenantId(tenantId); assetService.deleteAssetsByTenantId(tenantId); deviceService.deleteDevicesByTenantId(tenantId); - entityViewService.deleteEntityViewsByTenantId(tenantId); userService.deleteTenantAdmins(tenantId); ruleChainService.deleteRuleChainsByTenantId(tenantId); tenantDao.removeById(tenantId.getId());