thingsboard-memoizeit
Changes
application/src/main/java/org/thingsboard/server/service/install/DefaultDataUpdateService.java 4(+4 -0)
application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java 9(+9 -0)
application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java 134(+134 -0)
application/src/test/java/org/thingsboard/server/controller/nosql/EntityViewControllerNoSqlTest.java 24(+24 -0)
application/src/test/java/org/thingsboard/server/controller/sql/EntityViewControllerSqlTest.java 31(+31 -0)
common/data/src/main/java/org/thingsboard/server/common/data/objects/AttributesEntityView.java 52(+52 -0)
common/data/src/main/java/org/thingsboard/server/common/data/objects/TelemetryEntityView.java 48(+48 -0)
dao/src/main/resources/cassandra/schema.cql 42(+42 -0)
dao/src/main/resources/sql/schema.sql 14(+14 -0)
Details
diff --git a/application/src/main/data/upgrade/2.1.1/schema_update.cql b/application/src/main/data/upgrade/2.1.1/schema_update.cql
new file mode 100644
index 0000000..d9ba517
--- /dev/null
+++ b/application/src/main/data/upgrade/2.1.1/schema_update.cql
@@ -0,0 +1,92 @@
+--
+-- 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 0000000..3670aad
--- /dev/null
+++ b/application/src/main/data/upgrade/2.1.1/schema_update.sql
@@ -0,0 +1,31 @@
+--
+-- 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_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),
+ search_text varchar(255),
+ additional_info varchar
+);
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 de73fe0..af62e04 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);
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 0000000..fd3ccf2
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
@@ -0,0 +1,98 @@
+/**
+ * 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 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.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.
+ */
+@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);
+ }
+ }
+
+ @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);
+ }
+ }
+}
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 f863d0b..347b054 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 5daebcc..0194a5d 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 3a4a837..7d701b7 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);
}
diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml
index 743a860..be5149d 100644
--- a/application/src/main/resources/thingsboard.yml
+++ b/application/src/main/resources/thingsboard.yml
@@ -359,7 +359,7 @@ spring:
password: "${SPRING_DATASOURCE_PASSWORD:}"
# PostgreSQL DAO Configuration
-#spring:
+# spring:
# data:
# sql:
# repositories:
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 0000000..c7ac98d
--- /dev/null
+++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java
@@ -0,0 +1,134 @@
+/**
+ * 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;
+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.objects.AttributesEntityView;
+import org.thingsboard.server.common.data.objects.TelemetryEntityView;
+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;
+ private TelemetryEntityView obj;
+
+ @Before
+ public void beforeTest() throws Exception {
+ loginSysAdmin();
+
+ 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");
+
+ 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
+ public void afterTest() throws Exception {
+ loginSysAdmin();
+
+ doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
+ .andExpect(status().isOk());
+ }
+
+ @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 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);
+
+ 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/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);
+
+ doDelete("/api/entity-view/" + savedView.getId().getId().toString())
+ .andExpect(status().isOk());
+
+ doGet("/api/entity-view/" + savedView.getId().getId().toString())
+ .andExpect(status().isNotFound());
+ }
+}
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 f316051..a9e94e9 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
new file mode 100644
index 0000000..ad066fc
--- /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 0000000..76d9925
--- /dev/null
+++ b/application/src/test/java/org/thingsboard/server/controller/sql/EntityViewControllerSqlTest.java
@@ -0,0 +1,31 @@
+/**
+ * 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.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 {
+}
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 21de402..698a69e 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";
}
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 fe9c018..ef4994a 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 0000000..813a9ac
--- /dev/null
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java
@@ -0,0 +1,76 @@
+/**
+ * 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.*;
+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.objects.TelemetryEntityView;
+
+/**
+ * Created by Victor Basanets on 8/27/2017.
+ */
+
+@Data
+@AllArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class EntityView extends SearchTextBasedWithAdditionalInfo<EntityViewId>
+ implements HasName, HasTenantId, HasCustomerId {
+
+ private static final long serialVersionUID = 5582010124562018986L;
+
+ private EntityId entityId;
+ private TenantId tenantId;
+ private CustomerId customerId;
+ private String name;
+ private TelemetryEntityView keys;
+ private Long tsBegin;
+ private Long tsEnd;
+
+ public EntityView() {
+ super();
+ }
+
+ public EntityView(EntityViewId id) {
+ super(id);
+ }
+
+ public EntityView(EntityView entityView) {
+ super(entityView);
+ }
+
+ @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;
+ }
+}
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 ed4cf2f..4e35c0b 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!");
}
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 0000000..459dd99
--- /dev/null
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityViewId.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.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;
+
+/**
+ * Created by Victor Basanets on 8/27/2017.
+ */
+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;
+ }
+}
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 0000000..b1d270c
--- /dev/null
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/objects/AttributesEntityView.java
@@ -0,0 +1,52 @@
+/**
+ * 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<String> cs = new ArrayList<>();
+ private List<String> ss = new ArrayList<>();
+ private List<String> sh = new ArrayList<>();
+
+ public AttributesEntityView(List<String> cs,
+ List<String> ss,
+ List<String> 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());
+ }
+
+ @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
new file mode 100644
index 0000000..e7398e6
--- /dev/null
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/objects/TelemetryEntityView.java
@@ -0,0 +1,48 @@
+/**
+ * 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<String> timeseries;
+ private AttributesEntityView attributes;
+
+ public TelemetryEntityView(List<String> timeseries, AttributesEntityView attributes) {
+
+ this.timeseries = new ArrayList<>(timeseries);
+ this.attributes = attributes;
+ }
+
+ 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/EntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java
new file mode 100644
index 0000000..25404db
--- /dev/null
+++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java
@@ -0,0 +1,88 @@
+/**
+ * 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.id.EntityId;
+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<EntityView> {
+
+ /**
+ * 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<EntityView> 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<EntityView> 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<EntityView> findEntityViewByTenantIdAndEntityId(UUID tenantId,
+ UUID entityId,
+ 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<EntityView> findEntityViewsByTenantIdAndCustomerId(UUID tenantId,
+ 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<EntityView> findEntityViewsByTenantIdAndCustomerIdAndEntityId(UUID tenantId,
+ 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
new file mode 100644
index 0000000..943d35e
--- /dev/null
+++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java
@@ -0,0 +1,60 @@
+/**
+ * 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.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;
+import org.thingsboard.server.common.data.page.TextPageLink;
+
+/**
+ * Created by Victor Basanets on 8/27/2017.
+ */
+public interface EntityViewService {
+
+ EntityView findEntityViewById(EntityViewId entityViewId);
+
+ EntityView findEntityViewByTenantIdAndName(TenantId tenantId, String name);
+
+ EntityView saveEntityView(EntityView entityView);
+
+ EntityView assignEntityViewToCustomer(EntityViewId entityViewId, CustomerId customerId);
+
+ EntityView unassignEntityViewFromCustomer(EntityViewId entityViewId);
+
+ void deleteEntityView(EntityViewId entityViewId);
+
+ TextPageData<EntityView> findEntityViewByTenantId(TenantId tenantId, TextPageLink pageLink);
+
+ TextPageData<EntityView> findEntityViewByTenantIdAndEntityId(TenantId tenantId, EntityId entityId,
+ TextPageLink pageLink);
+
+ void deleteEntityViewByTenantId(TenantId tenantId);
+
+ TextPageData<EntityView> findEntityViewsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId,
+ TextPageLink pageLink);
+
+ TextPageData<EntityView> 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
new file mode 100644
index 0000000..6554083
--- /dev/null
+++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java
@@ -0,0 +1,276 @@
+/**
+ * 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.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.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 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;
+
+ @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);
+ validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId);
+ deleteEntityRelations(entityViewId);
+ EntityView entityView = entityViewDao.findById(entityViewId.getId());
+ List<Object> list = new ArrayList<>();
+ list.add(entityView.getTenantId());
+ list.add(entityView.getName());
+ entityViewDao.removeById(entityViewId.getId());
+ }
+
+ @Override
+ public TextPageData<EntityView> 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<EntityView> entityViews = entityViewDao.findEntityViewByTenantId(tenantId.getId(), pageLink);
+ return new TextPageData<>(entityViews, pageLink);
+ }
+
+ @Override
+ public TextPageData<EntityView> 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<EntityView> 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);
+ validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
+ tenantEntityViewRemover.removeEntities(tenantId);
+ }
+
+ @Override
+ public TextPageData<EntityView> 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<EntityView> entityViews = entityViewDao.findEntityViewsByTenantIdAndCustomerId(tenantId.getId(),
+ customerId.getId(), pageLink);
+
+ return new TextPageData<>(entityViews, pageLink);
+ }
+
+ @Override
+ public TextPageData<EntityView> 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<EntityView> 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);
+ validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
+ validateId(customerId, INCORRECT_CUSTOMER_ID + customerId);
+ new CustomerEntityViewsUnAssigner(tenantId).removeEntities(customerId);
+ }
+
+ private DataValidator<EntityView> entityViewValidator =
+ new DataValidator<EntityView>() {
+
+ @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(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!");
+ }
+ 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<TenantId, EntityView> tenantEntityViewRemover =
+ new PaginatedRemover<TenantId, EntityView>() {
+
+ @Override
+ protected List<EntityView> 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<CustomerId, EntityView> {
+
+ private TenantId tenantId;
+
+ CustomerEntityViewsUnAssigner(TenantId tenantId) {
+ this.tenantId = tenantId;
+ }
+
+ @Override
+ protected List<EntityView> findEntities(CustomerId id, TextPageLink pageLink) {
+ return entityViewDao.findEntityViewsByTenantIdAndCustomerId(tenantId.getId(), id.getId(), pageLink);
+ }
+
+ @Override
+ protected void removeEntity(EntityView entity) {
+ unassignEntityViewFromCustomer(new EntityViewId(entity.getUuidId()));
+ }
+ }
+}
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 3a934eb..d06ddbd 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";
@@ -144,6 +145,20 @@ public class ModelConstants {
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_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;
+ 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";
+ public static final String ENTITY_VIEW_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
+
+ /**
* Cassandra audit log constants.
*/
public static final String AUDIT_LOG_COLUMN_FAMILY_NAME = "audit_log";
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 0000000..65914dd
--- /dev/null
+++ b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EntityViewEntity.java
@@ -0,0 +1,146 @@
+/**
+ * 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.databind.JsonNode;
+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.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.UUID;
+
+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<EntityView> {
+
+ @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 = 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();
+ }
+
+ @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((TelemetryEntityView) entityView.getKeys().toObject(keys));
+// } 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
new file mode 100644
index 0000000..9136717
--- /dev/null
+++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityViewEntity.java
@@ -0,0 +1,150 @@
+/**
+ * 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.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.EntityType;
+import org.thingsboard.server.common.data.EntityView;
+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.*;
+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;
+
+/**
+ * Created by Victor Basanets on 8/30/2017.
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@Entity
+@TypeDef(name = "json", typeClass = JsonStringType.class)
+@Table(name = ModelConstants.ENTITY_VIEW_TABLE_FAMILY_NAME)
+public class EntityViewEntity extends BaseSqlEntity<EntityView> implements SearchTextEntity<EntityView> {
+
+ @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;
+
+ @Column(name = ModelConstants.ENTITY_VIEW_CUSTOMER_ID_PROPERTY)
+ private String customerId;
+
+ @Column(name = ModelConstants.ENTITY_VIEW_NAME_PROPERTY)
+ private String name;
+
+ @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_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;
+
+ private static final ObjectMapper mapper = new ObjectMapper();
+
+ 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());
+ this.entityType = entityView.getEntityId().getEntityType();
+ }
+ 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 = 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();
+ 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()));
+
+ if (entityId != null) {
+ entityView.setEntityId(EntityIdFactory.getByTypeAndId(entityType.name(), toUUID(entityId).toString()));
+ }
+ if (tenantId != null) {
+ entityView.setTenantId(new TenantId(toUUID(tenantId)));
+ }
+ if (customerId != null) {
+ entityView.setCustomerId(new CustomerId(toUUID(customerId)));
+ }
+ entityView.setName(name);
+ 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);
+ return entityView;
+ }
+}
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 0000000..27bd839
--- /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<EntityViewEntity, String> {
+
+ @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<EntityViewEntity> 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<EntityViewEntity> 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<EntityViewEntity> 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<EntityViewEntity> 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<EntityViewEntity> findAllByTenantIdAndCustomerIdAndIdIn(String tenantId,
+ String customerId,
+ List<String> entityViewsIds);
+
+ List<EntityViewEntity> findAllByTenantIdAndIdIn(String tenantId, List<String> 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 0000000..57b0afa
--- /dev/null
+++ b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java
@@ -0,0 +1,118 @@
+/**
+ * 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;
+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;
+
+/**
+ * Created by Victor Basanets on 8/31/2017.
+ */
+@Component
+@SqlDao
+public class JpaEntityViewDao extends JpaAbstractSearchTextDao<EntityViewEntity, EntityView>
+ implements EntityViewDao {
+
+ @Autowired
+ EntityViewRepository entityViewRepository;
+
+ @Override
+ protected Class<EntityViewEntity> getEntityClass() {
+ return EntityViewEntity.class;
+ }
+
+ @Override
+ protected CrudRepository<EntityViewEntity, String> getCrudRepository() {
+ return entityViewRepository;
+ }
+
+ @Override
+ public List<EntityView> 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<EntityView> findEntityViewByTenantIdAndName(UUID tenantId, String name) {
+ return Optional.ofNullable(
+ DaoUtil.getData(entityViewRepository.findByTenantIdAndName(fromTimeUUID(tenantId), name)));
+ }
+
+ @Override
+ public List<EntityView> 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<EntityView> 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<EntityView> 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())
+ ));
+ }
+}
dao/src/main/resources/cassandra/schema.cql 42(+42 -0)
diff --git a/dao/src/main/resources/cassandra/schema.cql b/dao/src/main/resources/cassandra/schema.cql
index f03122a..bdd413d 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);
dao/src/main/resources/sql/schema.sql 14(+14 -0)
diff --git a/dao/src/main/resources/sql/schema.sql b/dao/src/main/resources/sql/schema.sql
index 91e77da..ed3583c 100644
--- a/dao/src/main/resources/sql/schema.sql
+++ b/dao/src/main/resources/sql/schema.sql
@@ -251,3 +251,17 @@ 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,
+ 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),
+ search_text varchar(255),
+ additional_info varchar
+);
diff --git a/dao/src/test/resources/sql/drop-all-tables.sql b/dao/src/test/resources/sql/drop-all-tables.sql
index 23b6a56..ebc04b3 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