Commit bdc048c54833351ae5d7d0529947cb2fd16b5cae

Authored by volodymyr-babak
2 parents e5d664b4 e3976b31

Merge remote-tracking branch 'upstream/master' into feature/mqtt-plugin

Showing 64 changed files with 3225 additions and 253 deletions

Too many changes to show.

To preserve performance only 64 of 169 files are displayed.

... ... @@ -21,6 +21,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
21 21 import org.springframework.web.bind.annotation.*;
22 22 import org.thingsboard.server.common.data.Customer;
23 23 import org.thingsboard.server.common.data.asset.Asset;
  24 +import org.thingsboard.server.common.data.asset.TenantAssetType;
24 25 import org.thingsboard.server.common.data.id.AssetId;
25 26 import org.thingsboard.server.common.data.id.CustomerId;
26 27 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -136,13 +137,18 @@ public class AssetController extends BaseController {
136 137 @ResponseBody
137 138 public TextPageData<Asset> getTenantAssets(
138 139 @RequestParam int limit,
  140 + @RequestParam(required = false) String type,
139 141 @RequestParam(required = false) String textSearch,
140 142 @RequestParam(required = false) String idOffset,
141 143 @RequestParam(required = false) String textOffset) throws ThingsboardException {
142 144 try {
143 145 TenantId tenantId = getCurrentUser().getTenantId();
144 146 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
145   - return checkNotNull(assetService.findAssetsByTenantId(tenantId, pageLink));
  147 + if (type != null && type.trim().length()>0) {
  148 + return checkNotNull(assetService.findAssetsByTenantIdAndType(tenantId, type, pageLink));
  149 + } else {
  150 + return checkNotNull(assetService.findAssetsByTenantId(tenantId, pageLink));
  151 + }
146 152 } catch (Exception e) {
147 153 throw handleException(e);
148 154 }
... ... @@ -167,6 +173,7 @@ public class AssetController extends BaseController {
167 173 public TextPageData<Asset> getCustomerAssets(
168 174 @PathVariable("customerId") String strCustomerId,
169 175 @RequestParam int limit,
  176 + @RequestParam(required = false) String type,
170 177 @RequestParam(required = false) String textSearch,
171 178 @RequestParam(required = false) String idOffset,
172 179 @RequestParam(required = false) String textOffset) throws ThingsboardException {
... ... @@ -176,7 +183,11 @@ public class AssetController extends BaseController {
176 183 CustomerId customerId = new CustomerId(toUUID(strCustomerId));
177 184 checkCustomerId(customerId);
178 185 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
179   - return checkNotNull(assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink));
  186 + if (type != null && type.trim().length()>0) {
  187 + return checkNotNull(assetService.findAssetsByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
  188 + } else {
  189 + return checkNotNull(assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink));
  190 + }
180 191 } catch (Exception e) {
181 192 throw handleException(e);
182 193 }
... ... @@ -231,4 +242,18 @@ public class AssetController extends BaseController {
231 242 throw handleException(e);
232 243 }
233 244 }
  245 +
  246 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
  247 + @RequestMapping(value = "/asset/types", method = RequestMethod.GET)
  248 + @ResponseBody
  249 + public List<TenantAssetType> getAssetTypes() throws ThingsboardException {
  250 + try {
  251 + SecurityUser user = getCurrentUser();
  252 + TenantId tenantId = user.getTenantId();
  253 + ListenableFuture<List<TenantAssetType>> assetTypes = assetService.findAssetTypesByTenantId(tenantId);
  254 + return checkNotNull(assetTypes.get());
  255 + } catch (Exception e) {
  256 + throw handleException(e);
  257 + }
  258 + }
234 259 }
... ...
... ... @@ -21,6 +21,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
21 21 import org.springframework.web.bind.annotation.*;
22 22 import org.thingsboard.server.common.data.Customer;
23 23 import org.thingsboard.server.common.data.Device;
  24 +import org.thingsboard.server.common.data.TenantDeviceType;
24 25 import org.thingsboard.server.common.data.id.CustomerId;
25 26 import org.thingsboard.server.common.data.id.DeviceId;
26 27 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -166,13 +167,18 @@ public class DeviceController extends BaseController {
166 167 @ResponseBody
167 168 public TextPageData<Device> getTenantDevices(
168 169 @RequestParam int limit,
  170 + @RequestParam(required = false) String type,
169 171 @RequestParam(required = false) String textSearch,
170 172 @RequestParam(required = false) String idOffset,
171 173 @RequestParam(required = false) String textOffset) throws ThingsboardException {
172 174 try {
173 175 TenantId tenantId = getCurrentUser().getTenantId();
174 176 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
175   - return checkNotNull(deviceService.findDevicesByTenantId(tenantId, pageLink));
  177 + if (type != null && type.trim().length()>0) {
  178 + return checkNotNull(deviceService.findDevicesByTenantIdAndType(tenantId, type, pageLink));
  179 + } else {
  180 + return checkNotNull(deviceService.findDevicesByTenantId(tenantId, pageLink));
  181 + }
176 182 } catch (Exception e) {
177 183 throw handleException(e);
178 184 }
... ... @@ -197,6 +203,7 @@ public class DeviceController extends BaseController {
197 203 public TextPageData<Device> getCustomerDevices(
198 204 @PathVariable("customerId") String strCustomerId,
199 205 @RequestParam int limit,
  206 + @RequestParam(required = false) String type,
200 207 @RequestParam(required = false) String textSearch,
201 208 @RequestParam(required = false) String idOffset,
202 209 @RequestParam(required = false) String textOffset) throws ThingsboardException {
... ... @@ -206,7 +213,11 @@ public class DeviceController extends BaseController {
206 213 CustomerId customerId = new CustomerId(toUUID(strCustomerId));
207 214 checkCustomerId(customerId);
208 215 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
209   - return checkNotNull(deviceService.findDevicesByTenantIdAndCustomerId(tenantId, customerId, pageLink));
  216 + if (type != null && type.trim().length()>0) {
  217 + return checkNotNull(deviceService.findDevicesByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
  218 + } else {
  219 + return checkNotNull(deviceService.findDevicesByTenantIdAndCustomerId(tenantId, customerId, pageLink));
  220 + }
210 221 } catch (Exception e) {
211 222 throw handleException(e);
212 223 }
... ... @@ -261,4 +272,19 @@ public class DeviceController extends BaseController {
261 272 throw handleException(e);
262 273 }
263 274 }
  275 +
  276 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
  277 + @RequestMapping(value = "/device/types", method = RequestMethod.GET)
  278 + @ResponseBody
  279 + public List<TenantDeviceType> getDeviceTypes() throws ThingsboardException {
  280 + try {
  281 + SecurityUser user = getCurrentUser();
  282 + TenantId tenantId = user.getTenantId();
  283 + ListenableFuture<List<TenantDeviceType>> deviceTypes = deviceService.findDeviceTypesByTenantId(tenantId);
  284 + return checkNotNull(deviceTypes.get());
  285 + } catch (Exception e) {
  286 + throw handleException(e);
  287 + }
  288 + }
  289 +
264 290 }
... ...
... ... @@ -21,6 +21,7 @@ import org.springframework.web.bind.annotation.*;
21 21 import org.thingsboard.server.common.data.id.EntityId;
22 22 import org.thingsboard.server.common.data.id.EntityIdFactory;
23 23 import org.thingsboard.server.common.data.relation.EntityRelation;
  24 +import org.thingsboard.server.common.data.relation.EntityRelationInfo;
24 25 import org.thingsboard.server.dao.relation.EntityRelationsQuery;
25 26 import org.thingsboard.server.exception.ThingsboardErrorCode;
26 27 import org.thingsboard.server.exception.ThingsboardException;
... ... @@ -128,6 +129,21 @@ public class EntityRelationController extends BaseController {
128 129 }
129 130
130 131 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
  132 + @RequestMapping(value = "/relations/info", method = RequestMethod.GET, params = {"fromId", "fromType"})
  133 + @ResponseBody
  134 + public List<EntityRelationInfo> findInfoByFrom(@RequestParam("fromId") String strFromId, @RequestParam("fromType") String strFromType) throws ThingsboardException {
  135 + checkParameter("fromId", strFromId);
  136 + checkParameter("fromType", strFromType);
  137 + EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
  138 + checkEntityId(entityId);
  139 + try {
  140 + return checkNotNull(relationService.findInfoByFrom(entityId).get());
  141 + } catch (Exception e) {
  142 + throw handleException(e);
  143 + }
  144 + }
  145 +
  146 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
131 147 @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"fromId", "fromType", "relationType"})
132 148 @ResponseBody
133 149 public List<EntityRelation> findByFrom(@RequestParam("fromId") String strFromId, @RequestParam("fromType") String strFromType
... ...
... ... @@ -19,12 +19,18 @@ server:
19 19 address: "${HTTP_BIND_ADDRESS:0.0.0.0}"
20 20 # Server bind port
21 21 port: "${HTTP_BIND_PORT:8080}"
22   -# Uncomment the following section to enable ssl
23   -# ssl:
24   -# key-store: classpath:keystore/keystore.p12
25   -# key-store-password: thingsboard
26   -# keyStoreType: PKCS12
27   -# keyAlias: tomcat
  22 + # Server SSL configuration
  23 + ssl:
  24 + # Enable/disable SSL support
  25 + enabled: "${SSL_ENABLED:false}"
  26 + # Path to the key store that holds the SSL certificate
  27 + key-store: "${SSL_KEY_STORE:classpath:keystore/keystore.p12}"
  28 + # Password used to access the key store
  29 + key-store-password: "${SSL_KEY_STORE_PASSWORD:thingsboard}"
  30 + # Type of the key store
  31 + key-store-type: "${SSL_KEY_STORE_TYPE:PKCS12}"
  32 + # Alias that identifies the key in the key store
  33 + key-alias: "${SSL_KEY_ALIAS:tomcat}"
28 34
29 35 # Zookeeper connection parameters. Used for service discovery.
30 36 zk:
... ... @@ -79,12 +85,18 @@ mqtt:
79 85 leak_detector_level: "${NETTY_LEASK_DETECTOR_LVL:DISABLED}"
80 86 boss_group_thread_count: "${NETTY_BOSS_GROUP_THREADS:1}"
81 87 worker_group_thread_count: "${NETTY_WORKER_GROUP_THREADS:12}"
82   -# Uncomment the following lines to enable ssl for MQTT
83   -# ssl:
84   -# key_store: mqttserver.jks
85   -# key_store_password: server_ks_password
86   -# key_password: server_key_password
87   -# key_store_type: JKS
  88 + # MQTT SSL configuration
  89 + ssl:
  90 + # Enable/disable SSL support
  91 + enabled: "${MQTT_SSL_ENABLED:false}"
  92 + # Path to the key store that holds the SSL certificate
  93 + key_store: "${MQTT_SSL_KEY_STORE:mqttserver.jks}"
  94 + # Password used to access the key store
  95 + key_store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}"
  96 + # Password used to access the key
  97 + key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}"
  98 + # Type of the key store
  99 + key_store_type: "${MQTT_SSL_KEY_STORE_TYPE:JKS}"
88 100
89 101 # CoAP server parameters
90 102 coap:
... ...
... ... @@ -98,13 +98,15 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppC
98 98 @IntegrationTest("server.port:0")
99 99 public abstract class AbstractControllerTest {
100 100
  101 + protected static final String TEST_TENANT_NAME = "TEST TENANT";
  102 +
101 103 protected static final String SYS_ADMIN_EMAIL = "sysadmin@thingsboard.org";
102 104 private static final String SYS_ADMIN_PASSWORD = "sysadmin";
103 105
104   - protected static final String TENANT_ADMIN_EMAIL = "tenant@thingsboard.org";
  106 + protected static final String TENANT_ADMIN_EMAIL = "testtenant@thingsboard.org";
105 107 private static final String TENANT_ADMIN_PASSWORD = "tenant";
106 108
107   - protected static final String CUSTOMER_USER_EMAIL = "customer@thingsboard.org";
  109 + protected static final String CUSTOMER_USER_EMAIL = "testcustomer@thingsboard.org";
108 110 private static final String CUSTOMER_USER_PASSWORD = "customer";
109 111
110 112 protected MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
... ... @@ -147,7 +149,7 @@ public abstract class AbstractControllerTest {
147 149 loginSysAdmin();
148 150
149 151 Tenant tenant = new Tenant();
150   - tenant.setTitle("Tenant");
  152 + tenant.setTitle(TEST_TENANT_NAME);
151 153 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
152 154 Assert.assertNotNull(savedTenant);
153 155 tenantId = savedTenant.getId();
... ...
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.controller;
  17 +
  18 +import static org.hamcrest.Matchers.containsString;
  19 +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
  20 +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
  21 +
  22 +import java.util.ArrayList;
  23 +import java.util.Collections;
  24 +import java.util.List;
  25 +
  26 +import org.apache.commons.lang3.RandomStringUtils;
  27 +import org.thingsboard.server.common.data.*;
  28 +import org.thingsboard.server.common.data.asset.Asset;
  29 +import org.thingsboard.server.common.data.asset.TenantAssetType;
  30 +import org.thingsboard.server.common.data.id.CustomerId;
  31 +import org.thingsboard.server.common.data.id.AssetId;
  32 +import org.thingsboard.server.common.data.page.TextPageData;
  33 +import org.thingsboard.server.common.data.page.TextPageLink;
  34 +import org.thingsboard.server.common.data.security.Authority;
  35 +import org.thingsboard.server.dao.model.ModelConstants;
  36 +import org.junit.After;
  37 +import org.junit.Assert;
  38 +import org.junit.Before;
  39 +import org.junit.Test;
  40 +
  41 +import com.datastax.driver.core.utils.UUIDs;
  42 +import com.fasterxml.jackson.core.type.TypeReference;
  43 +
  44 +public class AssetControllerTest extends AbstractControllerTest {
  45 +
  46 + private IdComparator<Asset> idComparator = new IdComparator<>();
  47 +
  48 + private Tenant savedTenant;
  49 + private User tenantAdmin;
  50 +
  51 + @Before
  52 + public void beforeTest() throws Exception {
  53 + loginSysAdmin();
  54 +
  55 + Tenant tenant = new Tenant();
  56 + tenant.setTitle("My tenant");
  57 + savedTenant = doPost("/api/tenant", tenant, Tenant.class);
  58 + Assert.assertNotNull(savedTenant);
  59 +
  60 + tenantAdmin = new User();
  61 + tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
  62 + tenantAdmin.setTenantId(savedTenant.getId());
  63 + tenantAdmin.setEmail("tenant2@thingsboard.org");
  64 + tenantAdmin.setFirstName("Joe");
  65 + tenantAdmin.setLastName("Downs");
  66 +
  67 + tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
  68 + }
  69 +
  70 + @After
  71 + public void afterTest() throws Exception {
  72 + loginSysAdmin();
  73 +
  74 + doDelete("/api/tenant/"+savedTenant.getId().getId().toString())
  75 + .andExpect(status().isOk());
  76 + }
  77 +
  78 + @Test
  79 + public void testSaveAsset() throws Exception {
  80 + Asset asset = new Asset();
  81 + asset.setName("My asset");
  82 + asset.setType("default");
  83 + Asset savedAsset = doPost("/api/asset", asset, Asset.class);
  84 +
  85 + Assert.assertNotNull(savedAsset);
  86 + Assert.assertNotNull(savedAsset.getId());
  87 + Assert.assertTrue(savedAsset.getCreatedTime() > 0);
  88 + Assert.assertEquals(savedTenant.getId(), savedAsset.getTenantId());
  89 + Assert.assertNotNull(savedAsset.getCustomerId());
  90 + Assert.assertEquals(NULL_UUID, savedAsset.getCustomerId().getId());
  91 + Assert.assertEquals(asset.getName(), savedAsset.getName());
  92 +
  93 + savedAsset.setName("My new asset");
  94 + doPost("/api/asset", savedAsset, Asset.class);
  95 +
  96 + Asset foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class);
  97 + Assert.assertEquals(foundAsset.getName(), savedAsset.getName());
  98 + }
  99 +
  100 + @Test
  101 + public void testFindAssetById() throws Exception {
  102 + Asset asset = new Asset();
  103 + asset.setName("My asset");
  104 + asset.setType("default");
  105 + Asset savedAsset = doPost("/api/asset", asset, Asset.class);
  106 + Asset foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class);
  107 + Assert.assertNotNull(foundAsset);
  108 + Assert.assertEquals(savedAsset, foundAsset);
  109 + }
  110 +
  111 + @Test
  112 + public void testFindAssetTypesByTenantId() throws Exception {
  113 + List<Asset> assets = new ArrayList<>();
  114 + for (int i=0;i<3;i++) {
  115 + Asset asset = new Asset();
  116 + asset.setName("My asset B"+i);
  117 + asset.setType("typeB");
  118 + assets.add(doPost("/api/asset", asset, Asset.class));
  119 + }
  120 + for (int i=0;i<7;i++) {
  121 + Asset asset = new Asset();
  122 + asset.setName("My asset C"+i);
  123 + asset.setType("typeC");
  124 + assets.add(doPost("/api/asset", asset, Asset.class));
  125 + }
  126 + for (int i=0;i<9;i++) {
  127 + Asset asset = new Asset();
  128 + asset.setName("My asset A"+i);
  129 + asset.setType("typeA");
  130 + assets.add(doPost("/api/asset", asset, Asset.class));
  131 + }
  132 + List<TenantAssetType> assetTypes = doGetTyped("/api/asset/types",
  133 + new TypeReference<List<TenantAssetType>>(){});
  134 +
  135 + Assert.assertNotNull(assetTypes);
  136 + Assert.assertEquals(3, assetTypes.size());
  137 + Assert.assertEquals("typeA", assetTypes.get(0).getType());
  138 + Assert.assertEquals("typeB", assetTypes.get(1).getType());
  139 + Assert.assertEquals("typeC", assetTypes.get(2).getType());
  140 + }
  141 +
  142 + @Test
  143 + public void testDeleteAsset() throws Exception {
  144 + Asset asset = new Asset();
  145 + asset.setName("My asset");
  146 + asset.setType("default");
  147 + Asset savedAsset = doPost("/api/asset", asset, Asset.class);
  148 +
  149 + doDelete("/api/asset/"+savedAsset.getId().getId().toString())
  150 + .andExpect(status().isOk());
  151 +
  152 + doGet("/api/asset/"+savedAsset.getId().getId().toString())
  153 + .andExpect(status().isNotFound());
  154 + }
  155 +
  156 + @Test
  157 + public void testSaveAssetWithEmptyType() throws Exception {
  158 + Asset asset = new Asset();
  159 + asset.setName("My asset");
  160 + doPost("/api/asset", asset)
  161 + .andExpect(status().isBadRequest())
  162 + .andExpect(statusReason(containsString("Asset type should be specified")));
  163 + }
  164 +
  165 + @Test
  166 + public void testSaveAssetWithEmptyName() throws Exception {
  167 + Asset asset = new Asset();
  168 + asset.setType("default");
  169 + doPost("/api/asset", asset)
  170 + .andExpect(status().isBadRequest())
  171 + .andExpect(statusReason(containsString("Asset name should be specified")));
  172 + }
  173 +
  174 + @Test
  175 + public void testAssignUnassignAssetToCustomer() throws Exception {
  176 + Asset asset = new Asset();
  177 + asset.setName("My asset");
  178 + asset.setType("default");
  179 + Asset savedAsset = doPost("/api/asset", asset, Asset.class);
  180 +
  181 + Customer customer = new Customer();
  182 + customer.setTitle("My customer");
  183 + Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
  184 +
  185 + Asset assignedAsset = doPost("/api/customer/" + savedCustomer.getId().getId().toString()
  186 + + "/asset/" + savedAsset.getId().getId().toString(), Asset.class);
  187 + Assert.assertEquals(savedCustomer.getId(), assignedAsset.getCustomerId());
  188 +
  189 + Asset foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class);
  190 + Assert.assertEquals(savedCustomer.getId(), foundAsset.getCustomerId());
  191 +
  192 + Asset unassignedAsset =
  193 + doDelete("/api/customer/asset/" + savedAsset.getId().getId().toString(), Asset.class);
  194 + Assert.assertEquals(ModelConstants.NULL_UUID, unassignedAsset.getCustomerId().getId());
  195 +
  196 + foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class);
  197 + Assert.assertEquals(ModelConstants.NULL_UUID, foundAsset.getCustomerId().getId());
  198 + }
  199 +
  200 + @Test
  201 + public void testAssignAssetToNonExistentCustomer() throws Exception {
  202 + Asset asset = new Asset();
  203 + asset.setName("My asset");
  204 + asset.setType("default");
  205 + Asset savedAsset = doPost("/api/asset", asset, Asset.class);
  206 +
  207 + doPost("/api/customer/" + UUIDs.timeBased().toString()
  208 + + "/asset/" + savedAsset.getId().getId().toString())
  209 + .andExpect(status().isNotFound());
  210 + }
  211 +
  212 + @Test
  213 + public void testAssignAssetToCustomerFromDifferentTenant() throws Exception {
  214 + loginSysAdmin();
  215 +
  216 + Tenant tenant2 = new Tenant();
  217 + tenant2.setTitle("Different tenant");
  218 + Tenant savedTenant2 = doPost("/api/tenant", tenant2, Tenant.class);
  219 + Assert.assertNotNull(savedTenant2);
  220 +
  221 + User tenantAdmin2 = new User();
  222 + tenantAdmin2.setAuthority(Authority.TENANT_ADMIN);
  223 + tenantAdmin2.setTenantId(savedTenant2.getId());
  224 + tenantAdmin2.setEmail("tenant3@thingsboard.org");
  225 + tenantAdmin2.setFirstName("Joe");
  226 + tenantAdmin2.setLastName("Downs");
  227 +
  228 + tenantAdmin2 = createUserAndLogin(tenantAdmin2, "testPassword1");
  229 +
  230 + Customer customer = new Customer();
  231 + customer.setTitle("Different customer");
  232 + Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
  233 +
  234 + login(tenantAdmin.getEmail(), "testPassword1");
  235 +
  236 + Asset asset = new Asset();
  237 + asset.setName("My asset");
  238 + asset.setType("default");
  239 + Asset savedAsset = doPost("/api/asset", asset, Asset.class);
  240 +
  241 + doPost("/api/customer/" + savedCustomer.getId().getId().toString()
  242 + + "/asset/" + savedAsset.getId().getId().toString())
  243 + .andExpect(status().isForbidden());
  244 +
  245 + loginSysAdmin();
  246 +
  247 + doDelete("/api/tenant/"+savedTenant2.getId().getId().toString())
  248 + .andExpect(status().isOk());
  249 + }
  250 +
  251 + @Test
  252 + public void testFindTenantAssets() throws Exception {
  253 + List<Asset> assets = new ArrayList<>();
  254 + for (int i=0;i<178;i++) {
  255 + Asset asset = new Asset();
  256 + asset.setName("Asset"+i);
  257 + asset.setType("default");
  258 + assets.add(doPost("/api/asset", asset, Asset.class));
  259 + }
  260 + List<Asset> loadedAssets = new ArrayList<>();
  261 + TextPageLink pageLink = new TextPageLink(23);
  262 + TextPageData<Asset> pageData = null;
  263 + do {
  264 + pageData = doGetTypedWithPageLink("/api/tenant/assets?",
  265 + new TypeReference<TextPageData<Asset>>(){}, pageLink);
  266 + loadedAssets.addAll(pageData.getData());
  267 + if (pageData.hasNext()) {
  268 + pageLink = pageData.getNextPageLink();
  269 + }
  270 + } while (pageData.hasNext());
  271 +
  272 + Collections.sort(assets, idComparator);
  273 + Collections.sort(loadedAssets, idComparator);
  274 +
  275 + Assert.assertEquals(assets, loadedAssets);
  276 + }
  277 +
  278 + @Test
  279 + public void testFindTenantAssetsByName() throws Exception {
  280 + String title1 = "Asset title 1";
  281 + List<Asset> assetsTitle1 = new ArrayList<>();
  282 + for (int i=0;i<143;i++) {
  283 + Asset asset = new Asset();
  284 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  285 + String name = title1+suffix;
  286 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  287 + asset.setName(name);
  288 + asset.setType("default");
  289 + assetsTitle1.add(doPost("/api/asset", asset, Asset.class));
  290 + }
  291 + String title2 = "Asset title 2";
  292 + List<Asset> assetsTitle2 = new ArrayList<>();
  293 + for (int i=0;i<75;i++) {
  294 + Asset asset = new Asset();
  295 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  296 + String name = title2+suffix;
  297 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  298 + asset.setName(name);
  299 + asset.setType("default");
  300 + assetsTitle2.add(doPost("/api/asset", asset, Asset.class));
  301 + }
  302 +
  303 + List<Asset> loadedAssetsTitle1 = new ArrayList<>();
  304 + TextPageLink pageLink = new TextPageLink(15, title1);
  305 + TextPageData<Asset> pageData = null;
  306 + do {
  307 + pageData = doGetTypedWithPageLink("/api/tenant/assets?",
  308 + new TypeReference<TextPageData<Asset>>(){}, pageLink);
  309 + loadedAssetsTitle1.addAll(pageData.getData());
  310 + if (pageData.hasNext()) {
  311 + pageLink = pageData.getNextPageLink();
  312 + }
  313 + } while (pageData.hasNext());
  314 +
  315 + Collections.sort(assetsTitle1, idComparator);
  316 + Collections.sort(loadedAssetsTitle1, idComparator);
  317 +
  318 + Assert.assertEquals(assetsTitle1, loadedAssetsTitle1);
  319 +
  320 + List<Asset> loadedAssetsTitle2 = new ArrayList<>();
  321 + pageLink = new TextPageLink(4, title2);
  322 + do {
  323 + pageData = doGetTypedWithPageLink("/api/tenant/assets?",
  324 + new TypeReference<TextPageData<Asset>>(){}, pageLink);
  325 + loadedAssetsTitle2.addAll(pageData.getData());
  326 + if (pageData.hasNext()) {
  327 + pageLink = pageData.getNextPageLink();
  328 + }
  329 + } while (pageData.hasNext());
  330 +
  331 + Collections.sort(assetsTitle2, idComparator);
  332 + Collections.sort(loadedAssetsTitle2, idComparator);
  333 +
  334 + Assert.assertEquals(assetsTitle2, loadedAssetsTitle2);
  335 +
  336 + for (Asset asset : loadedAssetsTitle1) {
  337 + doDelete("/api/asset/"+asset.getId().getId().toString())
  338 + .andExpect(status().isOk());
  339 + }
  340 +
  341 + pageLink = new TextPageLink(4, title1);
  342 + pageData = doGetTypedWithPageLink("/api/tenant/assets?",
  343 + new TypeReference<TextPageData<Asset>>(){}, pageLink);
  344 + Assert.assertFalse(pageData.hasNext());
  345 + Assert.assertEquals(0, pageData.getData().size());
  346 +
  347 + for (Asset asset : loadedAssetsTitle2) {
  348 + doDelete("/api/asset/"+asset.getId().getId().toString())
  349 + .andExpect(status().isOk());
  350 + }
  351 +
  352 + pageLink = new TextPageLink(4, title2);
  353 + pageData = doGetTypedWithPageLink("/api/tenant/assets?",
  354 + new TypeReference<TextPageData<Asset>>(){}, pageLink);
  355 + Assert.assertFalse(pageData.hasNext());
  356 + Assert.assertEquals(0, pageData.getData().size());
  357 + }
  358 +
  359 + @Test
  360 + public void testFindTenantAssetsByType() throws Exception {
  361 + String title1 = "Asset title 1";
  362 + String type1 = "typeA";
  363 + List<Asset> assetsType1 = new ArrayList<>();
  364 + for (int i=0;i<143;i++) {
  365 + Asset asset = new Asset();
  366 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  367 + String name = title1+suffix;
  368 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  369 + asset.setName(name);
  370 + asset.setType(type1);
  371 + assetsType1.add(doPost("/api/asset", asset, Asset.class));
  372 + }
  373 + String title2 = "Asset title 2";
  374 + String type2 = "typeB";
  375 + List<Asset> assetsType2 = new ArrayList<>();
  376 + for (int i=0;i<75;i++) {
  377 + Asset asset = new Asset();
  378 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  379 + String name = title2+suffix;
  380 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  381 + asset.setName(name);
  382 + asset.setType(type2);
  383 + assetsType2.add(doPost("/api/asset", asset, Asset.class));
  384 + }
  385 +
  386 + List<Asset> loadedAssetsType1 = new ArrayList<>();
  387 + TextPageLink pageLink = new TextPageLink(15);
  388 + TextPageData<Asset> pageData = null;
  389 + do {
  390 + pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&",
  391 + new TypeReference<TextPageData<Asset>>(){}, pageLink, type1);
  392 + loadedAssetsType1.addAll(pageData.getData());
  393 + if (pageData.hasNext()) {
  394 + pageLink = pageData.getNextPageLink();
  395 + }
  396 + } while (pageData.hasNext());
  397 +
  398 + Collections.sort(assetsType1, idComparator);
  399 + Collections.sort(loadedAssetsType1, idComparator);
  400 +
  401 + Assert.assertEquals(assetsType1, loadedAssetsType1);
  402 +
  403 + List<Asset> loadedAssetsType2 = new ArrayList<>();
  404 + pageLink = new TextPageLink(4);
  405 + do {
  406 + pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&",
  407 + new TypeReference<TextPageData<Asset>>(){}, pageLink, type2);
  408 + loadedAssetsType2.addAll(pageData.getData());
  409 + if (pageData.hasNext()) {
  410 + pageLink = pageData.getNextPageLink();
  411 + }
  412 + } while (pageData.hasNext());
  413 +
  414 + Collections.sort(assetsType2, idComparator);
  415 + Collections.sort(loadedAssetsType2, idComparator);
  416 +
  417 + Assert.assertEquals(assetsType2, loadedAssetsType2);
  418 +
  419 + for (Asset asset : loadedAssetsType1) {
  420 + doDelete("/api/asset/"+asset.getId().getId().toString())
  421 + .andExpect(status().isOk());
  422 + }
  423 +
  424 + pageLink = new TextPageLink(4);
  425 + pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&",
  426 + new TypeReference<TextPageData<Asset>>(){}, pageLink, type1);
  427 + Assert.assertFalse(pageData.hasNext());
  428 + Assert.assertEquals(0, pageData.getData().size());
  429 +
  430 + for (Asset asset : loadedAssetsType2) {
  431 + doDelete("/api/asset/"+asset.getId().getId().toString())
  432 + .andExpect(status().isOk());
  433 + }
  434 +
  435 + pageLink = new TextPageLink(4);
  436 + pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&",
  437 + new TypeReference<TextPageData<Asset>>(){}, pageLink, type2);
  438 + Assert.assertFalse(pageData.hasNext());
  439 + Assert.assertEquals(0, pageData.getData().size());
  440 + }
  441 +
  442 + @Test
  443 + public void testFindCustomerAssets() throws Exception {
  444 + Customer customer = new Customer();
  445 + customer.setTitle("Test customer");
  446 + customer = doPost("/api/customer", customer, Customer.class);
  447 + CustomerId customerId = customer.getId();
  448 +
  449 + List<Asset> assets = new ArrayList<>();
  450 + for (int i=0;i<128;i++) {
  451 + Asset asset = new Asset();
  452 + asset.setName("Asset"+i);
  453 + asset.setType("default");
  454 + asset = doPost("/api/asset", asset, Asset.class);
  455 + assets.add(doPost("/api/customer/" + customerId.getId().toString()
  456 + + "/asset/" + asset.getId().getId().toString(), Asset.class));
  457 + }
  458 +
  459 + List<Asset> loadedAssets = new ArrayList<>();
  460 + TextPageLink pageLink = new TextPageLink(23);
  461 + TextPageData<Asset> pageData = null;
  462 + do {
  463 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?",
  464 + new TypeReference<TextPageData<Asset>>(){}, pageLink);
  465 + loadedAssets.addAll(pageData.getData());
  466 + if (pageData.hasNext()) {
  467 + pageLink = pageData.getNextPageLink();
  468 + }
  469 + } while (pageData.hasNext());
  470 +
  471 + Collections.sort(assets, idComparator);
  472 + Collections.sort(loadedAssets, idComparator);
  473 +
  474 + Assert.assertEquals(assets, loadedAssets);
  475 + }
  476 +
  477 + @Test
  478 + public void testFindCustomerAssetsByName() throws Exception {
  479 + Customer customer = new Customer();
  480 + customer.setTitle("Test customer");
  481 + customer = doPost("/api/customer", customer, Customer.class);
  482 + CustomerId customerId = customer.getId();
  483 +
  484 + String title1 = "Asset title 1";
  485 + List<Asset> assetsTitle1 = new ArrayList<>();
  486 + for (int i=0;i<125;i++) {
  487 + Asset asset = new Asset();
  488 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  489 + String name = title1+suffix;
  490 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  491 + asset.setName(name);
  492 + asset.setType("default");
  493 + asset = doPost("/api/asset", asset, Asset.class);
  494 + assetsTitle1.add(doPost("/api/customer/" + customerId.getId().toString()
  495 + + "/asset/" + asset.getId().getId().toString(), Asset.class));
  496 + }
  497 + String title2 = "Asset title 2";
  498 + List<Asset> assetsTitle2 = new ArrayList<>();
  499 + for (int i=0;i<143;i++) {
  500 + Asset asset = new Asset();
  501 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  502 + String name = title2+suffix;
  503 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  504 + asset.setName(name);
  505 + asset.setType("default");
  506 + asset = doPost("/api/asset", asset, Asset.class);
  507 + assetsTitle2.add(doPost("/api/customer/" + customerId.getId().toString()
  508 + + "/asset/" + asset.getId().getId().toString(), Asset.class));
  509 + }
  510 +
  511 + List<Asset> loadedAssetsTitle1 = new ArrayList<>();
  512 + TextPageLink pageLink = new TextPageLink(15, title1);
  513 + TextPageData<Asset> pageData = null;
  514 + do {
  515 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?",
  516 + new TypeReference<TextPageData<Asset>>(){}, pageLink);
  517 + loadedAssetsTitle1.addAll(pageData.getData());
  518 + if (pageData.hasNext()) {
  519 + pageLink = pageData.getNextPageLink();
  520 + }
  521 + } while (pageData.hasNext());
  522 +
  523 + Collections.sort(assetsTitle1, idComparator);
  524 + Collections.sort(loadedAssetsTitle1, idComparator);
  525 +
  526 + Assert.assertEquals(assetsTitle1, loadedAssetsTitle1);
  527 +
  528 + List<Asset> loadedAssetsTitle2 = new ArrayList<>();
  529 + pageLink = new TextPageLink(4, title2);
  530 + do {
  531 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?",
  532 + new TypeReference<TextPageData<Asset>>(){}, pageLink);
  533 + loadedAssetsTitle2.addAll(pageData.getData());
  534 + if (pageData.hasNext()) {
  535 + pageLink = pageData.getNextPageLink();
  536 + }
  537 + } while (pageData.hasNext());
  538 +
  539 + Collections.sort(assetsTitle2, idComparator);
  540 + Collections.sort(loadedAssetsTitle2, idComparator);
  541 +
  542 + Assert.assertEquals(assetsTitle2, loadedAssetsTitle2);
  543 +
  544 + for (Asset asset : loadedAssetsTitle1) {
  545 + doDelete("/api/customer/asset/" + asset.getId().getId().toString())
  546 + .andExpect(status().isOk());
  547 + }
  548 +
  549 + pageLink = new TextPageLink(4, title1);
  550 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?",
  551 + new TypeReference<TextPageData<Asset>>(){}, pageLink);
  552 + Assert.assertFalse(pageData.hasNext());
  553 + Assert.assertEquals(0, pageData.getData().size());
  554 +
  555 + for (Asset asset : loadedAssetsTitle2) {
  556 + doDelete("/api/customer/asset/" + asset.getId().getId().toString())
  557 + .andExpect(status().isOk());
  558 + }
  559 +
  560 + pageLink = new TextPageLink(4, title2);
  561 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?",
  562 + new TypeReference<TextPageData<Asset>>(){}, pageLink);
  563 + Assert.assertFalse(pageData.hasNext());
  564 + Assert.assertEquals(0, pageData.getData().size());
  565 + }
  566 +
  567 + @Test
  568 + public void testFindCustomerAssetsByType() throws Exception {
  569 + Customer customer = new Customer();
  570 + customer.setTitle("Test customer");
  571 + customer = doPost("/api/customer", customer, Customer.class);
  572 + CustomerId customerId = customer.getId();
  573 +
  574 + String title1 = "Asset title 1";
  575 + String type1 = "typeC";
  576 + List<Asset> assetsType1 = new ArrayList<>();
  577 + for (int i=0;i<125;i++) {
  578 + Asset asset = new Asset();
  579 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  580 + String name = title1+suffix;
  581 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  582 + asset.setName(name);
  583 + asset.setType(type1);
  584 + asset = doPost("/api/asset", asset, Asset.class);
  585 + assetsType1.add(doPost("/api/customer/" + customerId.getId().toString()
  586 + + "/asset/" + asset.getId().getId().toString(), Asset.class));
  587 + }
  588 + String title2 = "Asset title 2";
  589 + String type2 = "typeD";
  590 + List<Asset> assetsType2 = new ArrayList<>();
  591 + for (int i=0;i<143;i++) {
  592 + Asset asset = new Asset();
  593 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  594 + String name = title2+suffix;
  595 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  596 + asset.setName(name);
  597 + asset.setType(type2);
  598 + asset = doPost("/api/asset", asset, Asset.class);
  599 + assetsType2.add(doPost("/api/customer/" + customerId.getId().toString()
  600 + + "/asset/" + asset.getId().getId().toString(), Asset.class));
  601 + }
  602 +
  603 + List<Asset> loadedAssetsType1 = new ArrayList<>();
  604 + TextPageLink pageLink = new TextPageLink(15);
  605 + TextPageData<Asset> pageData = null;
  606 + do {
  607 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&",
  608 + new TypeReference<TextPageData<Asset>>(){}, pageLink, type1);
  609 + loadedAssetsType1.addAll(pageData.getData());
  610 + if (pageData.hasNext()) {
  611 + pageLink = pageData.getNextPageLink();
  612 + }
  613 + } while (pageData.hasNext());
  614 +
  615 + Collections.sort(assetsType1, idComparator);
  616 + Collections.sort(loadedAssetsType1, idComparator);
  617 +
  618 + Assert.assertEquals(assetsType1, loadedAssetsType1);
  619 +
  620 + List<Asset> loadedAssetsType2 = new ArrayList<>();
  621 + pageLink = new TextPageLink(4);
  622 + do {
  623 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&",
  624 + new TypeReference<TextPageData<Asset>>(){}, pageLink, type2);
  625 + loadedAssetsType2.addAll(pageData.getData());
  626 + if (pageData.hasNext()) {
  627 + pageLink = pageData.getNextPageLink();
  628 + }
  629 + } while (pageData.hasNext());
  630 +
  631 + Collections.sort(assetsType2, idComparator);
  632 + Collections.sort(loadedAssetsType2, idComparator);
  633 +
  634 + Assert.assertEquals(assetsType2, loadedAssetsType2);
  635 +
  636 + for (Asset asset : loadedAssetsType1) {
  637 + doDelete("/api/customer/asset/" + asset.getId().getId().toString())
  638 + .andExpect(status().isOk());
  639 + }
  640 +
  641 + pageLink = new TextPageLink(4);
  642 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&",
  643 + new TypeReference<TextPageData<Asset>>(){}, pageLink, type1);
  644 + Assert.assertFalse(pageData.hasNext());
  645 + Assert.assertEquals(0, pageData.getData().size());
  646 +
  647 + for (Asset asset : loadedAssetsType2) {
  648 + doDelete("/api/customer/asset/" + asset.getId().getId().toString())
  649 + .andExpect(status().isOk());
  650 + }
  651 +
  652 + pageLink = new TextPageLink(4);
  653 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&",
  654 + new TypeReference<TextPageData<Asset>>(){}, pageLink, type2);
  655 + Assert.assertFalse(pageData.hasNext());
  656 + Assert.assertEquals(0, pageData.getData().size());
  657 + }
  658 +
  659 +}
... ...
... ... @@ -24,10 +24,7 @@ import java.util.Collections;
24 24 import java.util.List;
25 25
26 26 import org.apache.commons.lang3.RandomStringUtils;
27   -import org.thingsboard.server.common.data.Customer;
28   -import org.thingsboard.server.common.data.Device;
29   -import org.thingsboard.server.common.data.Tenant;
30   -import org.thingsboard.server.common.data.User;
  27 +import org.thingsboard.server.common.data.*;
31 28 import org.thingsboard.server.common.data.id.CustomerId;
32 29 import org.thingsboard.server.common.data.id.DeviceCredentialsId;
33 30 import org.thingsboard.server.common.data.id.DeviceId;
... ... @@ -83,6 +80,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
83 80 public void testSaveDevice() throws Exception {
84 81 Device device = new Device();
85 82 device.setName("My device");
  83 + device.setType("default");
86 84 Device savedDevice = doPost("/api/device", device, Device.class);
87 85
88 86 Assert.assertNotNull(savedDevice);
... ... @@ -114,16 +112,49 @@ public class DeviceControllerTest extends AbstractControllerTest {
114 112 public void testFindDeviceById() throws Exception {
115 113 Device device = new Device();
116 114 device.setName("My device");
  115 + device.setType("default");
117 116 Device savedDevice = doPost("/api/device", device, Device.class);
118 117 Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class);
119 118 Assert.assertNotNull(foundDevice);
120 119 Assert.assertEquals(savedDevice, foundDevice);
121 120 }
  121 +
  122 + @Test
  123 + public void testFindDeviceTypesByTenantId() throws Exception {
  124 + List<Device> devices = new ArrayList<>();
  125 + for (int i=0;i<3;i++) {
  126 + Device device = new Device();
  127 + device.setName("My device B"+i);
  128 + device.setType("typeB");
  129 + devices.add(doPost("/api/device", device, Device.class));
  130 + }
  131 + for (int i=0;i<7;i++) {
  132 + Device device = new Device();
  133 + device.setName("My device C"+i);
  134 + device.setType("typeC");
  135 + devices.add(doPost("/api/device", device, Device.class));
  136 + }
  137 + for (int i=0;i<9;i++) {
  138 + Device device = new Device();
  139 + device.setName("My device A"+i);
  140 + device.setType("typeA");
  141 + devices.add(doPost("/api/device", device, Device.class));
  142 + }
  143 + List<TenantDeviceType> deviceTypes = doGetTyped("/api/device/types",
  144 + new TypeReference<List<TenantDeviceType>>(){});
  145 +
  146 + Assert.assertNotNull(deviceTypes);
  147 + Assert.assertEquals(3, deviceTypes.size());
  148 + Assert.assertEquals("typeA", deviceTypes.get(0).getType());
  149 + Assert.assertEquals("typeB", deviceTypes.get(1).getType());
  150 + Assert.assertEquals("typeC", deviceTypes.get(2).getType());
  151 + }
122 152
123 153 @Test
124 154 public void testDeleteDevice() throws Exception {
125 155 Device device = new Device();
126 156 device.setName("My device");
  157 + device.setType("default");
127 158 Device savedDevice = doPost("/api/device", device, Device.class);
128 159
129 160 doDelete("/api/device/"+savedDevice.getId().getId().toString())
... ... @@ -132,10 +163,20 @@ public class DeviceControllerTest extends AbstractControllerTest {
132 163 doGet("/api/device/"+savedDevice.getId().getId().toString())
133 164 .andExpect(status().isNotFound());
134 165 }
135   -
  166 +
  167 + @Test
  168 + public void testSaveDeviceWithEmptyType() throws Exception {
  169 + Device device = new Device();
  170 + device.setName("My device");
  171 + doPost("/api/device", device)
  172 + .andExpect(status().isBadRequest())
  173 + .andExpect(statusReason(containsString("Device type should be specified")));
  174 + }
  175 +
136 176 @Test
137 177 public void testSaveDeviceWithEmptyName() throws Exception {
138 178 Device device = new Device();
  179 + device.setType("default");
139 180 doPost("/api/device", device)
140 181 .andExpect(status().isBadRequest())
141 182 .andExpect(statusReason(containsString("Device name should be specified")));
... ... @@ -145,6 +186,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
145 186 public void testAssignUnassignDeviceToCustomer() throws Exception {
146 187 Device device = new Device();
147 188 device.setName("My device");
  189 + device.setType("default");
148 190 Device savedDevice = doPost("/api/device", device, Device.class);
149 191
150 192 Customer customer = new Customer();
... ... @@ -170,6 +212,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
170 212 public void testAssignDeviceToNonExistentCustomer() throws Exception {
171 213 Device device = new Device();
172 214 device.setName("My device");
  215 + device.setType("default");
173 216 Device savedDevice = doPost("/api/device", device, Device.class);
174 217
175 218 doPost("/api/customer/" + UUIDs.timeBased().toString()
... ... @@ -203,6 +246,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
203 246
204 247 Device device = new Device();
205 248 device.setName("My device");
  249 + device.setType("default");
206 250 Device savedDevice = doPost("/api/device", device, Device.class);
207 251
208 252 doPost("/api/customer/" + savedCustomer.getId().getId().toString()
... ... @@ -219,6 +263,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
219 263 public void testFindDeviceCredentialsByDeviceId() throws Exception {
220 264 Device device = new Device();
221 265 device.setName("My device");
  266 + device.setType("default");
222 267 Device savedDevice = doPost("/api/device", device, Device.class);
223 268 DeviceCredentials deviceCredentials =
224 269 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
... ... @@ -229,6 +274,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
229 274 public void testSaveDeviceCredentials() throws Exception {
230 275 Device device = new Device();
231 276 device.setName("My device");
  277 + device.setType("default");
232 278 Device savedDevice = doPost("/api/device", device, Device.class);
233 279 DeviceCredentials deviceCredentials =
234 280 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
... ... @@ -255,6 +301,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
255 301 public void testSaveDeviceCredentialsWithEmptyCredentialsType() throws Exception {
256 302 Device device = new Device();
257 303 device.setName("My device");
  304 + device.setType("default");
258 305 Device savedDevice = doPost("/api/device", device, Device.class);
259 306 DeviceCredentials deviceCredentials =
260 307 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
... ... @@ -268,6 +315,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
268 315 public void testSaveDeviceCredentialsWithEmptyCredentialsId() throws Exception {
269 316 Device device = new Device();
270 317 device.setName("My device");
  318 + device.setType("default");
271 319 Device savedDevice = doPost("/api/device", device, Device.class);
272 320 DeviceCredentials deviceCredentials =
273 321 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
... ... @@ -281,6 +329,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
281 329 public void testSaveNonExistentDeviceCredentials() throws Exception {
282 330 Device device = new Device();
283 331 device.setName("My device");
  332 + device.setType("default");
284 333 Device savedDevice = doPost("/api/device", device, Device.class);
285 334 DeviceCredentials deviceCredentials =
286 335 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
... ... @@ -298,6 +347,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
298 347 public void testSaveDeviceCredentialsWithNonExistentDevice() throws Exception {
299 348 Device device = new Device();
300 349 device.setName("My device");
  350 + device.setType("default");
301 351 Device savedDevice = doPost("/api/device", device, Device.class);
302 352 DeviceCredentials deviceCredentials =
303 353 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
... ... @@ -307,9 +357,10 @@ public class DeviceControllerTest extends AbstractControllerTest {
307 357 }
308 358
309 359 @Test
310   - public void testSaveDeviceCredentialsWithInvalidCredemtialsIdLength() throws Exception {
  360 + public void testSaveDeviceCredentialsWithInvalidCredentialsIdLength() throws Exception {
311 361 Device device = new Device();
312 362 device.setName("My device");
  363 + device.setType("default");
313 364 Device savedDevice = doPost("/api/device", device, Device.class);
314 365 DeviceCredentials deviceCredentials =
315 366 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
... ... @@ -325,6 +376,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
325 376 for (int i=0;i<178;i++) {
326 377 Device device = new Device();
327 378 device.setName("Device"+i);
  379 + device.setType("default");
328 380 devices.add(doPost("/api/device", device, Device.class));
329 381 }
330 382 List<Device> loadedDevices = new ArrayList<>();
... ... @@ -355,6 +407,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
355 407 String name = title1+suffix;
356 408 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
357 409 device.setName(name);
  410 + device.setType("default");
358 411 devicesTitle1.add(doPost("/api/device", device, Device.class));
359 412 }
360 413 String title2 = "Device title 2";
... ... @@ -365,6 +418,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
365 418 String name = title2+suffix;
366 419 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
367 420 device.setName(name);
  421 + device.setType("default");
368 422 devicesTitle2.add(doPost("/api/device", device, Device.class));
369 423 }
370 424
... ... @@ -423,6 +477,89 @@ public class DeviceControllerTest extends AbstractControllerTest {
423 477 Assert.assertFalse(pageData.hasNext());
424 478 Assert.assertEquals(0, pageData.getData().size());
425 479 }
  480 +
  481 + @Test
  482 + public void testFindTenantDevicesByType() throws Exception {
  483 + String title1 = "Device title 1";
  484 + String type1 = "typeA";
  485 + List<Device> devicesType1 = new ArrayList<>();
  486 + for (int i=0;i<143;i++) {
  487 + Device device = new Device();
  488 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  489 + String name = title1+suffix;
  490 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  491 + device.setName(name);
  492 + device.setType(type1);
  493 + devicesType1.add(doPost("/api/device", device, Device.class));
  494 + }
  495 + String title2 = "Device title 2";
  496 + String type2 = "typeB";
  497 + List<Device> devicesType2 = new ArrayList<>();
  498 + for (int i=0;i<75;i++) {
  499 + Device device = new Device();
  500 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  501 + String name = title2+suffix;
  502 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  503 + device.setName(name);
  504 + device.setType(type2);
  505 + devicesType2.add(doPost("/api/device", device, Device.class));
  506 + }
  507 +
  508 + List<Device> loadedDevicesType1 = new ArrayList<>();
  509 + TextPageLink pageLink = new TextPageLink(15);
  510 + TextPageData<Device> pageData = null;
  511 + do {
  512 + pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&",
  513 + new TypeReference<TextPageData<Device>>(){}, pageLink, type1);
  514 + loadedDevicesType1.addAll(pageData.getData());
  515 + if (pageData.hasNext()) {
  516 + pageLink = pageData.getNextPageLink();
  517 + }
  518 + } while (pageData.hasNext());
  519 +
  520 + Collections.sort(devicesType1, idComparator);
  521 + Collections.sort(loadedDevicesType1, idComparator);
  522 +
  523 + Assert.assertEquals(devicesType1, loadedDevicesType1);
  524 +
  525 + List<Device> loadedDevicesType2 = new ArrayList<>();
  526 + pageLink = new TextPageLink(4);
  527 + do {
  528 + pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&",
  529 + new TypeReference<TextPageData<Device>>(){}, pageLink, type2);
  530 + loadedDevicesType2.addAll(pageData.getData());
  531 + if (pageData.hasNext()) {
  532 + pageLink = pageData.getNextPageLink();
  533 + }
  534 + } while (pageData.hasNext());
  535 +
  536 + Collections.sort(devicesType2, idComparator);
  537 + Collections.sort(loadedDevicesType2, idComparator);
  538 +
  539 + Assert.assertEquals(devicesType2, loadedDevicesType2);
  540 +
  541 + for (Device device : loadedDevicesType1) {
  542 + doDelete("/api/device/"+device.getId().getId().toString())
  543 + .andExpect(status().isOk());
  544 + }
  545 +
  546 + pageLink = new TextPageLink(4);
  547 + pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&",
  548 + new TypeReference<TextPageData<Device>>(){}, pageLink, type1);
  549 + Assert.assertFalse(pageData.hasNext());
  550 + Assert.assertEquals(0, pageData.getData().size());
  551 +
  552 + for (Device device : loadedDevicesType2) {
  553 + doDelete("/api/device/"+device.getId().getId().toString())
  554 + .andExpect(status().isOk());
  555 + }
  556 +
  557 + pageLink = new TextPageLink(4);
  558 + pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&",
  559 + new TypeReference<TextPageData<Device>>(){}, pageLink, type2);
  560 + Assert.assertFalse(pageData.hasNext());
  561 + Assert.assertEquals(0, pageData.getData().size());
  562 + }
426 563
427 564 @Test
428 565 public void testFindCustomerDevices() throws Exception {
... ... @@ -435,6 +572,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
435 572 for (int i=0;i<128;i++) {
436 573 Device device = new Device();
437 574 device.setName("Device"+i);
  575 + device.setType("default");
438 576 device = doPost("/api/device", device, Device.class);
439 577 devices.add(doPost("/api/customer/" + customerId.getId().toString()
440 578 + "/device/" + device.getId().getId().toString(), Device.class));
... ... @@ -473,6 +611,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
473 611 String name = title1+suffix;
474 612 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
475 613 device.setName(name);
  614 + device.setType("default");
476 615 device = doPost("/api/device", device, Device.class);
477 616 devicesTitle1.add(doPost("/api/customer/" + customerId.getId().toString()
478 617 + "/device/" + device.getId().getId().toString(), Device.class));
... ... @@ -485,6 +624,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
485 624 String name = title2+suffix;
486 625 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
487 626 device.setName(name);
  627 + device.setType("default");
488 628 device = doPost("/api/device", device, Device.class);
489 629 devicesTitle2.add(doPost("/api/customer/" + customerId.getId().toString()
490 630 + "/device/" + device.getId().getId().toString(), Device.class));
... ... @@ -546,4 +686,96 @@ public class DeviceControllerTest extends AbstractControllerTest {
546 686 Assert.assertEquals(0, pageData.getData().size());
547 687 }
548 688
  689 + @Test
  690 + public void testFindCustomerDevicesByType() throws Exception {
  691 + Customer customer = new Customer();
  692 + customer.setTitle("Test customer");
  693 + customer = doPost("/api/customer", customer, Customer.class);
  694 + CustomerId customerId = customer.getId();
  695 +
  696 + String title1 = "Device title 1";
  697 + String type1 = "typeC";
  698 + List<Device> devicesType1 = new ArrayList<>();
  699 + for (int i=0;i<125;i++) {
  700 + Device device = new Device();
  701 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  702 + String name = title1+suffix;
  703 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  704 + device.setName(name);
  705 + device.setType(type1);
  706 + device = doPost("/api/device", device, Device.class);
  707 + devicesType1.add(doPost("/api/customer/" + customerId.getId().toString()
  708 + + "/device/" + device.getId().getId().toString(), Device.class));
  709 + }
  710 + String title2 = "Device title 2";
  711 + String type2 = "typeD";
  712 + List<Device> devicesType2 = new ArrayList<>();
  713 + for (int i=0;i<143;i++) {
  714 + Device device = new Device();
  715 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  716 + String name = title2+suffix;
  717 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  718 + device.setName(name);
  719 + device.setType(type2);
  720 + device = doPost("/api/device", device, Device.class);
  721 + devicesType2.add(doPost("/api/customer/" + customerId.getId().toString()
  722 + + "/device/" + device.getId().getId().toString(), Device.class));
  723 + }
  724 +
  725 + List<Device> loadedDevicesType1 = new ArrayList<>();
  726 + TextPageLink pageLink = new TextPageLink(15);
  727 + TextPageData<Device> pageData = null;
  728 + do {
  729 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&",
  730 + new TypeReference<TextPageData<Device>>(){}, pageLink, type1);
  731 + loadedDevicesType1.addAll(pageData.getData());
  732 + if (pageData.hasNext()) {
  733 + pageLink = pageData.getNextPageLink();
  734 + }
  735 + } while (pageData.hasNext());
  736 +
  737 + Collections.sort(devicesType1, idComparator);
  738 + Collections.sort(loadedDevicesType1, idComparator);
  739 +
  740 + Assert.assertEquals(devicesType1, loadedDevicesType1);
  741 +
  742 + List<Device> loadedDevicesType2 = new ArrayList<>();
  743 + pageLink = new TextPageLink(4);
  744 + do {
  745 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&",
  746 + new TypeReference<TextPageData<Device>>(){}, pageLink, type2);
  747 + loadedDevicesType2.addAll(pageData.getData());
  748 + if (pageData.hasNext()) {
  749 + pageLink = pageData.getNextPageLink();
  750 + }
  751 + } while (pageData.hasNext());
  752 +
  753 + Collections.sort(devicesType2, idComparator);
  754 + Collections.sort(loadedDevicesType2, idComparator);
  755 +
  756 + Assert.assertEquals(devicesType2, loadedDevicesType2);
  757 +
  758 + for (Device device : loadedDevicesType1) {
  759 + doDelete("/api/customer/device/" + device.getId().getId().toString())
  760 + .andExpect(status().isOk());
  761 + }
  762 +
  763 + pageLink = new TextPageLink(4);
  764 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&",
  765 + new TypeReference<TextPageData<Device>>(){}, pageLink, type1);
  766 + Assert.assertFalse(pageData.hasNext());
  767 + Assert.assertEquals(0, pageData.getData().size());
  768 +
  769 + for (Device device : loadedDevicesType2) {
  770 + doDelete("/api/customer/device/" + device.getId().getId().toString())
  771 + .andExpect(status().isOk());
  772 + }
  773 +
  774 + pageLink = new TextPageLink(4);
  775 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&",
  776 + new TypeReference<TextPageData<Device>>(){}, pageLink, type2);
  777 + Assert.assertFalse(pageData.hasNext());
  778 + Assert.assertEquals(0, pageData.getData().size());
  779 + }
  780 +
549 781 }
... ...
... ... @@ -130,7 +130,7 @@ public class TenantControllerTest extends AbstractControllerTest {
130 130 Assert.assertEquals(tenants, loadedTenants);
131 131
132 132 for (Tenant tenant : loadedTenants) {
133   - if (!tenant.getTitle().equals("Tenant")) {
  133 + if (!tenant.getTitle().equals(TEST_TENANT_NAME)) {
134 134 doDelete("/api/tenant/"+tenant.getId().getId().toString())
135 135 .andExpect(status().isOk());
136 136 }
... ...
... ... @@ -182,7 +182,7 @@ public class UserControllerTest extends AbstractControllerTest {
182 182 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
183 183 Assert.assertNotNull(savedTenant);
184 184
185   - String email = "tenant@thingsboard.org";
  185 + String email = TENANT_ADMIN_EMAIL;
186 186 User user = new User();
187 187 user.setAuthority(Authority.TENANT_ADMIN);
188 188 user.setTenantId(savedTenant.getId());
... ...
... ... @@ -47,6 +47,7 @@ public class HttpDeviceApiTest extends AbstractControllerTest {
47 47 loginTenantAdmin();
48 48 device = new Device();
49 49 device.setName("My device");
  50 + device.setType("default");
50 51 device = doPost("/api/device", device, Device.class);
51 52
52 53 deviceCredentials =
... ...
... ... @@ -20,7 +20,7 @@ import org.thingsboard.server.common.data.id.TenantId;
20 20
21 21 import com.fasterxml.jackson.databind.JsonNode;
22 22
23   -public class Customer extends ContactBased<CustomerId>{
  23 +public class Customer extends ContactBased<CustomerId> implements HasName {
24 24
25 25 private static final long serialVersionUID = -1599722990298929275L;
26 26
... ... @@ -59,6 +59,11 @@ public class Customer extends ContactBased<CustomerId>{
59 59 this.title = title;
60 60 }
61 61
  62 + @Override
  63 + public String getName() {
  64 + return title;
  65 + }
  66 +
62 67 public JsonNode getAdditionalInfo() {
63 68 return additionalInfo;
64 69 }
... ...
... ... @@ -19,7 +19,7 @@ import org.thingsboard.server.common.data.id.CustomerId;
19 19 import org.thingsboard.server.common.data.id.DashboardId;
20 20 import org.thingsboard.server.common.data.id.TenantId;
21 21
22   -public class DashboardInfo extends SearchTextBased<DashboardId> {
  22 +public class DashboardInfo extends SearchTextBased<DashboardId> implements HasName {
23 23
24 24 private TenantId tenantId;
25 25 private CustomerId customerId;
... ... @@ -65,6 +65,11 @@ public class DashboardInfo extends SearchTextBased<DashboardId> {
65 65 }
66 66
67 67 @Override
  68 + public String getName() {
  69 + return title;
  70 + }
  71 +
  72 + @Override
68 73 public String getSearchText() {
69 74 return title;
70 75 }
... ...
... ... @@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.id.TenantId;
21 21
22 22 import com.fasterxml.jackson.databind.JsonNode;
23 23
24   -public class Device extends SearchTextBased<DeviceId> {
  24 +public class Device extends SearchTextBased<DeviceId> implements HasName {
25 25
26 26 private static final long serialVersionUID = 2807343040519543363L;
27 27
... ... @@ -64,6 +64,7 @@ public class Device extends SearchTextBased<DeviceId> {
64 64 this.customerId = customerId;
65 65 }
66 66
  67 + @Override
67 68 public String getName() {
68 69 return name;
69 70 }
... ...
... ... @@ -13,34 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
  16 +package org.thingsboard.server.common.data;
16 17
17   -.md-panel {
18   - &.tb-aliases-device-select-panel {
19   - position: absolute;
20   - }
21   -}
  18 +public interface HasName {
22 19
23   -.tb-aliases-device-select-panel {
24   - max-height: 150px;
25   - @media (min-height: 350px) {
26   - max-height: 250px;
27   - }
28   - min-width: 300px;
29   - background: white;
30   - border-radius: 4px;
31   - box-shadow: 0 7px 8px -4px rgba(0, 0, 0, 0.2),
32   - 0 13px 19px 2px rgba(0, 0, 0, 0.14),
33   - 0 5px 24px 4px rgba(0, 0, 0, 0.12);
34   - overflow-x: hidden;
35   - overflow-y: auto;
36   - md-content {
37   - background-color: #fff;
38   - }
39   -}
  20 + String getName();
40 21
41   -.tb-aliases-device-select {
42   - span {
43   - pointer-events: all;
44   - cursor: pointer;
45   - }
46 22 }
... ...
... ... @@ -19,7 +19,7 @@ import org.thingsboard.server.common.data.id.TenantId;
19 19
20 20 import com.fasterxml.jackson.databind.JsonNode;
21 21
22   -public class Tenant extends ContactBased<TenantId>{
  22 +public class Tenant extends ContactBased<TenantId> implements HasName {
23 23
24 24 private static final long serialVersionUID = 8057243243859922101L;
25 25
... ... @@ -50,6 +50,11 @@ public class Tenant extends ContactBased<TenantId>{
50 50 this.title = title;
51 51 }
52 52
  53 + @Override
  54 + public String getName() {
  55 + return title;
  56 + }
  57 +
53 58 public String getRegion() {
54 59 return region;
55 60 }
... ...
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data;
  17 +
  18 +import org.thingsboard.server.common.data.id.TenantId;
  19 +
  20 +public class TenantDeviceType {
  21 +
  22 + private static final long serialVersionUID = 8057240243859922101L;
  23 +
  24 + private String type;
  25 + private TenantId tenantId;
  26 +
  27 + public TenantDeviceType() {
  28 + super();
  29 + }
  30 +
  31 + public TenantDeviceType(String type, TenantId tenantId) {
  32 + this.type = type;
  33 + this.tenantId = tenantId;
  34 + }
  35 +
  36 + public String getType() {
  37 + return type;
  38 + }
  39 +
  40 + public void setType(String type) {
  41 + this.type = type;
  42 + }
  43 +
  44 + public TenantId getTenantId() {
  45 + return tenantId;
  46 + }
  47 +
  48 + public void setTenantId(TenantId tenantId) {
  49 + this.tenantId = tenantId;
  50 + }
  51 +
  52 + @Override
  53 + public int hashCode() {
  54 + int result = type != null ? type.hashCode() : 0;
  55 + result = 31 * result + (tenantId != null ? tenantId.hashCode() : 0);
  56 + return result;
  57 + }
  58 +
  59 + @Override
  60 + public boolean equals(Object o) {
  61 + if (this == o) return true;
  62 + if (o == null || getClass() != o.getClass()) return false;
  63 +
  64 + TenantDeviceType that = (TenantDeviceType) o;
  65 +
  66 + if (type != null ? !type.equals(that.type) : that.type != null) return false;
  67 + return tenantId != null ? tenantId.equals(that.tenantId) : that.tenantId == null;
  68 +
  69 + }
  70 +
  71 + @Override
  72 + public String toString() {
  73 + final StringBuilder sb = new StringBuilder("TenantDeviceType{");
  74 + sb.append("type='").append(type).append('\'');
  75 + sb.append(", tenantId=").append(tenantId);
  76 + sb.append('}');
  77 + return sb.toString();
  78 + }
  79 +}
... ...
... ... @@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.security.Authority;
22 22
23 23 import com.fasterxml.jackson.databind.JsonNode;
24 24
25   -public class User extends SearchTextBased<UserId> {
  25 +public class User extends SearchTextBased<UserId> implements HasName {
26 26
27 27 private static final long serialVersionUID = 8250339805336035966L;
28 28
... ... @@ -77,6 +77,11 @@ public class User extends SearchTextBased<UserId> {
77 77 this.email = email;
78 78 }
79 79
  80 + @Override
  81 + public String getName() {
  82 + return email;
  83 + }
  84 +
80 85 public Authority getAuthority() {
81 86 return authority;
82 87 }
... ...
... ... @@ -18,13 +18,14 @@ package org.thingsboard.server.common.data.alarm;
18 18 import com.fasterxml.jackson.databind.JsonNode;
19 19 import lombok.Data;
20 20 import org.thingsboard.server.common.data.BaseData;
  21 +import org.thingsboard.server.common.data.HasName;
21 22 import org.thingsboard.server.common.data.id.EntityId;
22 23
23 24 /**
24 25 * Created by ashvayka on 11.05.17.
25 26 */
26 27 @Data
27   -public class Alarm extends BaseData<AlarmId> {
  28 +public class Alarm extends BaseData<AlarmId> implements HasName {
28 29
29 30 private long startTs;
30 31 private long endTs;
... ... @@ -37,4 +38,8 @@ public class Alarm extends BaseData<AlarmId> {
37 38 private JsonNode details;
38 39 private boolean propagate;
39 40
  41 + @Override
  42 + public String getName() {
  43 + return type;
  44 + }
40 45 }
... ...
... ... @@ -16,12 +16,13 @@
16 16 package org.thingsboard.server.common.data.asset;
17 17
18 18 import com.fasterxml.jackson.databind.JsonNode;
  19 +import org.thingsboard.server.common.data.HasName;
19 20 import org.thingsboard.server.common.data.SearchTextBased;
20 21 import org.thingsboard.server.common.data.id.AssetId;
21 22 import org.thingsboard.server.common.data.id.CustomerId;
22 23 import org.thingsboard.server.common.data.id.TenantId;
23 24
24   -public class Asset extends SearchTextBased<AssetId> {
  25 +public class Asset extends SearchTextBased<AssetId> implements HasName {
25 26
26 27 private static final long serialVersionUID = 2807343040519543363L;
27 28
... ... @@ -64,6 +65,7 @@ public class Asset extends SearchTextBased<AssetId> {
64 65 this.customerId = customerId;
65 66 }
66 67
  68 + @Override
67 69 public String getName() {
68 70 return name;
69 71 }
... ...
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.asset;
  17 +
  18 +import org.thingsboard.server.common.data.id.TenantId;
  19 +
  20 +public class TenantAssetType {
  21 +
  22 + private static final long serialVersionUID = 8057290243855622101L;
  23 +
  24 + private String type;
  25 + private TenantId tenantId;
  26 +
  27 + public TenantAssetType() {
  28 + super();
  29 + }
  30 +
  31 + public TenantAssetType(String type, TenantId tenantId) {
  32 + this.type = type;
  33 + this.tenantId = tenantId;
  34 + }
  35 +
  36 + public String getType() {
  37 + return type;
  38 + }
  39 +
  40 + public void setType(String type) {
  41 + this.type = type;
  42 + }
  43 +
  44 + public TenantId getTenantId() {
  45 + return tenantId;
  46 + }
  47 +
  48 + public void setTenantId(TenantId tenantId) {
  49 + this.tenantId = tenantId;
  50 + }
  51 +
  52 + @Override
  53 + public int hashCode() {
  54 + int result = type != null ? type.hashCode() : 0;
  55 + result = 31 * result + (tenantId != null ? tenantId.hashCode() : 0);
  56 + return result;
  57 + }
  58 +
  59 + @Override
  60 + public boolean equals(Object o) {
  61 + if (this == o) return true;
  62 + if (o == null || getClass() != o.getClass()) return false;
  63 +
  64 + TenantAssetType that = (TenantAssetType) o;
  65 +
  66 + if (type != null ? !type.equals(that.type) : that.type != null) return false;
  67 + return tenantId != null ? tenantId.equals(that.tenantId) : that.tenantId == null;
  68 +
  69 + }
  70 +
  71 + @Override
  72 + public String toString() {
  73 + final StringBuilder sb = new StringBuilder("TenantAssetType{");
  74 + sb.append("type='").append(type).append('\'');
  75 + sb.append(", tenantId=").append(tenantId);
  76 + sb.append('}');
  77 + return sb.toString();
  78 + }
  79 +}
... ...
... ... @@ -15,13 +15,14 @@
15 15 */
16 16 package org.thingsboard.server.common.data.plugin;
17 17
  18 +import org.thingsboard.server.common.data.HasName;
18 19 import org.thingsboard.server.common.data.SearchTextBased;
19 20 import org.thingsboard.server.common.data.id.PluginId;
20 21 import org.thingsboard.server.common.data.id.TenantId;
21 22
22 23 import com.fasterxml.jackson.databind.JsonNode;
23 24
24   -public class PluginMetaData extends SearchTextBased<PluginId> {
  25 +public class PluginMetaData extends SearchTextBased<PluginId> implements HasName {
25 26
26 27 private static final long serialVersionUID = 1L;
27 28
... ... @@ -75,6 +76,7 @@ public class PluginMetaData extends SearchTextBased<PluginId> {
75 76 this.tenantId = tenantId;
76 77 }
77 78
  79 + @Override
78 80 public String getName() {
79 81 return name;
80 82 }
... ...
... ... @@ -47,11 +47,11 @@ public class EntityRelation {
47 47 this.additionalInfo = additionalInfo;
48 48 }
49 49
50   - public EntityRelation(EntityRelation device) {
51   - this.from = device.getFrom();
52   - this.to = device.getTo();
53   - this.type = device.getType();
54   - this.additionalInfo = device.getAdditionalInfo();
  50 + public EntityRelation(EntityRelation entityRelation) {
  51 + this.from = entityRelation.getFrom();
  52 + this.to = entityRelation.getTo();
  53 + this.type = entityRelation.getType();
  54 + this.additionalInfo = entityRelation.getAdditionalInfo();
55 55 }
56 56
57 57 public EntityId getFrom() {
... ...
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package org.thingsboard.server.common.data.relation;
  18 +
  19 +public class EntityRelationInfo extends EntityRelation {
  20 +
  21 + private static final long serialVersionUID = 2807343097519543363L;
  22 +
  23 + private String toName;
  24 +
  25 + public EntityRelationInfo() {
  26 + super();
  27 + }
  28 +
  29 + public EntityRelationInfo(EntityRelation entityRelation) {
  30 + super(entityRelation);
  31 + }
  32 +
  33 + public String getToName() {
  34 + return toName;
  35 + }
  36 +
  37 + public void setToName(String toName) {
  38 + this.toName = toName;
  39 + }
  40 +
  41 + @Override
  42 + public boolean equals(Object o) {
  43 + if (this == o) return true;
  44 + if (o == null || getClass() != o.getClass()) return false;
  45 + if (!super.equals(o)) return false;
  46 +
  47 + EntityRelationInfo that = (EntityRelationInfo) o;
  48 +
  49 + return toName != null ? toName.equals(that.toName) : that.toName == null;
  50 +
  51 + }
  52 +
  53 + @Override
  54 + public int hashCode() {
  55 + int result = super.hashCode();
  56 + result = 31 * result + (toName != null ? toName.hashCode() : 0);
  57 + return result;
  58 + }
  59 +}
... ...
... ... @@ -17,6 +17,7 @@ package org.thingsboard.server.common.data.rule;
17 17
18 18 import lombok.Data;
19 19 import lombok.ToString;
  20 +import org.thingsboard.server.common.data.HasName;
20 21 import org.thingsboard.server.common.data.SearchTextBased;
21 22 import org.thingsboard.server.common.data.id.CustomerId;
22 23 import org.thingsboard.server.common.data.id.RuleId;
... ... @@ -26,7 +27,7 @@ import com.fasterxml.jackson.databind.JsonNode;
26 27 import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
27 28
28 29 @Data
29   -public class RuleMetaData extends SearchTextBased<RuleId> {
  30 +public class RuleMetaData extends SearchTextBased<RuleId> implements HasName {
30 31
31 32 private static final long serialVersionUID = -5656679015122935465L;
32 33
... ... @@ -66,4 +67,9 @@ public class RuleMetaData extends SearchTextBased<RuleId> {
66 67 return name;
67 68 }
68 69
  70 + @Override
  71 + public String getName() {
  72 + return name;
  73 + }
  74 +
69 75 }
... ...
... ... @@ -28,6 +28,10 @@ import java.util.Optional;
28 28 */
29 29 public interface AlarmService {
30 30
  31 + Alarm findAlarmById(AlarmId alarmId);
  32 +
  33 + ListenableFuture<Alarm> findAlarmByIdAsync(AlarmId alarmId);
  34 +
31 35 Optional<Alarm> saveIfNotExists(Alarm alarm);
32 36
33 37 ListenableFuture<Boolean> updateAlarm(Alarm alarm);
... ...
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.alarm;
  17 +
  18 +import com.google.common.util.concurrent.ListenableFuture;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.springframework.stereotype.Service;
  21 +import org.thingsboard.server.common.data.alarm.Alarm;
  22 +import org.thingsboard.server.common.data.alarm.AlarmId;
  23 +import org.thingsboard.server.common.data.alarm.AlarmQuery;
  24 +import org.thingsboard.server.common.data.page.TimePageData;
  25 +
  26 +import java.util.Optional;
  27 +
  28 +@Service
  29 +@Slf4j
  30 +public class BaseAlarmService implements AlarmService {
  31 +
  32 + @Override
  33 + public Alarm findAlarmById(AlarmId alarmId) {
  34 + return null;
  35 + }
  36 +
  37 + @Override
  38 + public ListenableFuture<Alarm> findAlarmByIdAsync(AlarmId alarmId) {
  39 + return null;
  40 + }
  41 +
  42 + @Override
  43 + public Optional<Alarm> saveIfNotExists(Alarm alarm) {
  44 + return null;
  45 + }
  46 +
  47 + @Override
  48 + public ListenableFuture<Boolean> updateAlarm(Alarm alarm) {
  49 + return null;
  50 + }
  51 +
  52 + @Override
  53 + public ListenableFuture<Boolean> ackAlarm(Alarm alarm) {
  54 + return null;
  55 + }
  56 +
  57 + @Override
  58 + public ListenableFuture<Boolean> clearAlarm(AlarmId alarmId) {
  59 + return null;
  60 + }
  61 +
  62 + @Override
  63 + public ListenableFuture<TimePageData<Alarm>> findAlarms(AlarmQuery query) {
  64 + return null;
  65 + }
  66 +}
... ...
... ... @@ -16,12 +16,11 @@
16 16 package org.thingsboard.server.dao.asset;
17 17
18 18 import com.google.common.util.concurrent.ListenableFuture;
19   -import org.thingsboard.server.common.data.Device;
20 19 import org.thingsboard.server.common.data.asset.Asset;
21 20 import org.thingsboard.server.common.data.page.TextPageLink;
22 21 import org.thingsboard.server.dao.Dao;
23 22 import org.thingsboard.server.dao.model.AssetEntity;
24   -import org.thingsboard.server.dao.model.DeviceEntity;
  23 +import org.thingsboard.server.dao.model.TenantAssetTypeEntity;
25 24
26 25 import java.util.List;
27 26 import java.util.Optional;
... ... @@ -51,6 +50,16 @@ public interface AssetDao extends Dao<AssetEntity> {
51 50 List<AssetEntity> findAssetsByTenantId(UUID tenantId, TextPageLink pageLink);
52 51
53 52 /**
  53 + * Find assets by tenantId, type and page link.
  54 + *
  55 + * @param tenantId the tenantId
  56 + * @param type the type
  57 + * @param pageLink the page link
  58 + * @return the list of asset objects
  59 + */
  60 + List<AssetEntity> findAssetsByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink);
  61 +
  62 + /**
54 63 * Find assets by tenantId and assets Ids.
55 64 *
56 65 * @param tenantId the tenantId
... ... @@ -70,6 +79,17 @@ public interface AssetDao extends Dao<AssetEntity> {
70 79 List<AssetEntity> findAssetsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink);
71 80
72 81 /**
  82 + * Find assets by tenantId, customerId, type and page link.
  83 + *
  84 + * @param tenantId the tenantId
  85 + * @param customerId the customerId
  86 + * @param type the type
  87 + * @param pageLink the page link
  88 + * @return the list of asset objects
  89 + */
  90 + List<AssetEntity> findAssetsByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink);
  91 +
  92 + /**
73 93 * Find assets by tenantId, customerId and assets Ids.
74 94 *
75 95 * @param tenantId the tenantId
... ... @@ -87,4 +107,12 @@ public interface AssetDao extends Dao<AssetEntity> {
87 107 * @return the optional asset object
88 108 */
89 109 Optional<AssetEntity> findAssetsByTenantIdAndName(UUID tenantId, String name);
  110 +
  111 + /**
  112 + * Find tenants asset types.
  113 + *
  114 + * @return the list of tenant asset type objects
  115 + */
  116 + ListenableFuture<List<TenantAssetTypeEntity>> findTenantAssetTypesAsync();
  117 +
90 118 }
... ...
... ... @@ -15,7 +15,12 @@
15 15 */
16 16 package org.thingsboard.server.dao.asset;
17 17
  18 +import com.datastax.driver.core.ResultSet;
  19 +import com.datastax.driver.core.ResultSetFuture;
18 20 import com.datastax.driver.core.querybuilder.Select;
  21 +import com.datastax.driver.mapping.Result;
  22 +import com.google.common.base.Function;
  23 +import com.google.common.util.concurrent.Futures;
19 24 import com.google.common.util.concurrent.ListenableFuture;
20 25 import lombok.extern.slf4j.Slf4j;
21 26 import org.springframework.stereotype.Component;
... ... @@ -23,7 +28,9 @@ import org.thingsboard.server.common.data.asset.Asset;
23 28 import org.thingsboard.server.common.data.page.TextPageLink;
24 29 import org.thingsboard.server.dao.AbstractSearchTextDao;
25 30 import org.thingsboard.server.dao.model.AssetEntity;
  31 +import org.thingsboard.server.dao.model.TenantAssetTypeEntity;
26 32
  33 +import javax.annotation.Nullable;
27 34 import java.util.*;
28 35
29 36 import static com.datastax.driver.core.querybuilder.QueryBuilder.*;
... ... @@ -60,6 +67,16 @@ public class AssetDaoImpl extends AbstractSearchTextDao<AssetEntity> implements
60 67 }
61 68
62 69 @Override
  70 + public List<AssetEntity> findAssetsByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink) {
  71 + log.debug("Try to find assets by tenantId [{}], type [{}] and pageLink [{}]", tenantId, type, pageLink);
  72 + List<AssetEntity> assetEntities = findPageWithTextSearch(ASSET_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
  73 + Arrays.asList(eq(ASSET_TYPE_PROPERTY, type),
  74 + eq(ASSET_TENANT_ID_PROPERTY, tenantId)), pageLink);
  75 + log.trace("Found assets [{}] by tenantId [{}], type [{}] and pageLink [{}]", assetEntities, tenantId, type, pageLink);
  76 + return assetEntities;
  77 + }
  78 +
  79 + @Override
63 80 public ListenableFuture<List<AssetEntity>> findAssetsByTenantIdAndIdsAsync(UUID tenantId, List<UUID> assetIds) {
64 81 log.debug("Try to find assets by tenantId [{}] and asset Ids [{}]", tenantId, assetIds);
65 82 Select select = select().from(getColumnFamilyName());
... ... @@ -82,6 +99,19 @@ public class AssetDaoImpl extends AbstractSearchTextDao<AssetEntity> implements
82 99 }
83 100
84 101 @Override
  102 + public List<AssetEntity> findAssetsByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink) {
  103 + log.debug("Try to find assets by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", tenantId, customerId, type, pageLink);
  104 + List<AssetEntity> assetEntities = findPageWithTextSearch(ASSET_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
  105 + Arrays.asList(eq(ASSET_TYPE_PROPERTY, type),
  106 + eq(ASSET_CUSTOMER_ID_PROPERTY, customerId),
  107 + eq(ASSET_TENANT_ID_PROPERTY, tenantId)),
  108 + pageLink);
  109 +
  110 + log.trace("Found assets [{}] by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", assetEntities, tenantId, customerId, type, pageLink);
  111 + return assetEntities;
  112 + }
  113 +
  114 + @Override
85 115 public ListenableFuture<List<AssetEntity>> findAssetsByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> assetIds) {
86 116 log.debug("Try to find assets by tenantId [{}], customerId [{}] and asset Ids [{}]", tenantId, customerId, assetIds);
87 117 Select select = select().from(getColumnFamilyName());
... ... @@ -101,4 +131,24 @@ public class AssetDaoImpl extends AbstractSearchTextDao<AssetEntity> implements
101 131 return Optional.ofNullable(findOneByStatement(query));
102 132 }
103 133
  134 + @Override
  135 + public ListenableFuture<List<TenantAssetTypeEntity>> findTenantAssetTypesAsync() {
  136 + Select statement = select().distinct().column(ASSET_TYPE_PROPERTY).column(ASSET_TENANT_ID_PROPERTY).from(ASSET_TYPES_BY_TENANT_VIEW_NAME);
  137 + statement.setConsistencyLevel(cluster.getDefaultReadConsistencyLevel());
  138 + ResultSetFuture resultSetFuture = getSession().executeAsync(statement);
  139 + ListenableFuture<List<TenantAssetTypeEntity>> result = Futures.transform(resultSetFuture, new Function<ResultSet, List<TenantAssetTypeEntity>>() {
  140 + @Nullable
  141 + @Override
  142 + public List<TenantAssetTypeEntity> apply(@Nullable ResultSet resultSet) {
  143 + Result<TenantAssetTypeEntity> result = cluster.getMapper(TenantAssetTypeEntity.class).map(resultSet);
  144 + if (result != null) {
  145 + return result.all();
  146 + } else {
  147 + return Collections.emptyList();
  148 + }
  149 + }
  150 + });
  151 + return result;
  152 + }
  153 +
104 154 }
... ...
... ... @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.asset;
17 17
18 18 import com.google.common.util.concurrent.ListenableFuture;
19 19 import org.thingsboard.server.common.data.asset.Asset;
  20 +import org.thingsboard.server.common.data.asset.TenantAssetType;
20 21 import org.thingsboard.server.common.data.id.AssetId;
21 22 import org.thingsboard.server.common.data.id.CustomerId;
22 23 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -34,7 +35,7 @@ public interface AssetService {
34 35
35 36 Optional<Asset> findAssetByTenantIdAndName(TenantId tenantId, String name);
36 37
37   - Asset saveAsset(Asset device);
  38 + Asset saveAsset(Asset asset);
38 39
39 40 Asset assignAssetToCustomer(AssetId assetId, CustomerId customerId);
40 41
... ... @@ -44,16 +45,21 @@ public interface AssetService {
44 45
45 46 TextPageData<Asset> findAssetsByTenantId(TenantId tenantId, TextPageLink pageLink);
46 47
  48 + TextPageData<Asset> findAssetsByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink);
  49 +
47 50 ListenableFuture<List<Asset>> findAssetsByTenantIdAndIdsAsync(TenantId tenantId, List<AssetId> assetIds);
48 51
49 52 void deleteAssetsByTenantId(TenantId tenantId);
50 53
51 54 TextPageData<Asset> findAssetsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink);
52 55
  56 + TextPageData<Asset> findAssetsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, TextPageLink pageLink);
  57 +
53 58 ListenableFuture<List<Asset>> findAssetsByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<AssetId> assetIds);
54 59
55 60 void unassignCustomerAssets(TenantId tenantId, CustomerId customerId);
56 61
57 62 ListenableFuture<List<Asset>> findAssetsByQuery(AssetSearchQuery query);
58 63
  64 + ListenableFuture<List<TenantAssetType>> findAssetTypesByTenantId(TenantId tenantId);
59 65 }
... ...
... ... @@ -26,6 +26,7 @@ import org.springframework.stereotype.Service;
26 26 import org.springframework.util.StringUtils;
27 27 import org.thingsboard.server.common.data.EntityType;
28 28 import org.thingsboard.server.common.data.asset.Asset;
  29 +import org.thingsboard.server.common.data.asset.TenantAssetType;
29 30 import org.thingsboard.server.common.data.id.AssetId;
30 31 import org.thingsboard.server.common.data.id.CustomerId;
31 32 import org.thingsboard.server.common.data.id.EntityId;
... ... @@ -34,12 +35,9 @@ import org.thingsboard.server.common.data.page.TextPageData;
34 35 import org.thingsboard.server.common.data.page.TextPageLink;
35 36 import org.thingsboard.server.common.data.relation.EntityRelation;
36 37 import org.thingsboard.server.dao.customer.CustomerDao;
37   -import org.thingsboard.server.dao.entity.BaseEntityService;
  38 +import org.thingsboard.server.dao.entity.AbstractEntityService;
38 39 import org.thingsboard.server.dao.exception.DataValidationException;
39   -import org.thingsboard.server.dao.model.AssetEntity;
40   -import org.thingsboard.server.dao.model.CustomerEntity;
41   -import org.thingsboard.server.dao.model.TenantEntity;
42   -import org.thingsboard.server.dao.relation.EntityRelationsQuery;
  40 +import org.thingsboard.server.dao.model.*;
43 41 import org.thingsboard.server.dao.relation.EntitySearchDirection;
44 42 import org.thingsboard.server.dao.service.DataValidator;
45 43 import org.thingsboard.server.dao.service.PaginatedRemover;
... ... @@ -57,7 +55,7 @@ import static org.thingsboard.server.dao.service.Validator.*;
57 55
58 56 @Service
59 57 @Slf4j
60   -public class BaseAssetService extends BaseEntityService implements AssetService {
  58 +public class BaseAssetService extends AbstractEntityService implements AssetService {
61 59
62 60 @Autowired
63 61 private AssetDao assetDao;
... ... @@ -132,7 +130,18 @@ public class BaseAssetService extends BaseEntityService implements AssetService
132 130 validatePageLink(pageLink, "Incorrect page link " + pageLink);
133 131 List<AssetEntity> assetEntities = assetDao.findAssetsByTenantId(tenantId.getId(), pageLink);
134 132 List<Asset> assets = convertDataList(assetEntities);
135   - return new TextPageData<Asset>(assets, pageLink);
  133 + return new TextPageData<>(assets, pageLink);
  134 + }
  135 +
  136 + @Override
  137 + public TextPageData<Asset> findAssetsByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink) {
  138 + log.trace("Executing findAssetsByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink);
  139 + validateId(tenantId, "Incorrect tenantId " + tenantId);
  140 + validateString(type, "Incorrect type " + type);
  141 + validatePageLink(pageLink, "Incorrect page link " + pageLink);
  142 + List<AssetEntity> assetEntities = assetDao.findAssetsByTenantIdAndType(tenantId.getId(), type, pageLink);
  143 + List<Asset> assets = convertDataList(assetEntities);
  144 + return new TextPageData<>(assets, pageLink);
136 145 }
137 146
138 147 @Override
... ... @@ -159,7 +168,19 @@ public class BaseAssetService extends BaseEntityService implements AssetService
159 168 validatePageLink(pageLink, "Incorrect page link " + pageLink);
160 169 List<AssetEntity> assetEntities = assetDao.findAssetsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink);
161 170 List<Asset> assets = convertDataList(assetEntities);
162   - return new TextPageData<Asset>(assets, pageLink);
  171 + return new TextPageData<>(assets, pageLink);
  172 + }
  173 +
  174 + @Override
  175 + public TextPageData<Asset> findAssetsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, TextPageLink pageLink) {
  176 + log.trace("Executing findAssetsByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}], type [{}], pageLink [{}]", tenantId, customerId, type, pageLink);
  177 + validateId(tenantId, "Incorrect tenantId " + tenantId);
  178 + validateId(customerId, "Incorrect customerId " + customerId);
  179 + validateString(type, "Incorrect type " + type);
  180 + validatePageLink(pageLink, "Incorrect page link " + pageLink);
  181 + List<AssetEntity> assetEntities = assetDao.findAssetsByTenantIdAndCustomerIdAndType(tenantId.getId(), customerId.getId(), type, pageLink);
  182 + List<Asset> assets = convertDataList(assetEntities);
  183 + return new TextPageData<>(assets, pageLink);
163 184 }
164 185
165 186 @Override
... ... @@ -207,6 +228,25 @@ public class BaseAssetService extends BaseEntityService implements AssetService
207 228 return assets;
208 229 }
209 230
  231 + @Override
  232 + public ListenableFuture<List<TenantAssetType>> findAssetTypesByTenantId(TenantId tenantId) {
  233 + log.trace("Executing findAssetTypesByTenantId, tenantId [{}]", tenantId);
  234 + validateId(tenantId, "Incorrect tenantId " + tenantId);
  235 + ListenableFuture<List<TenantAssetTypeEntity>> tenantAssetTypeEntities = assetDao.findTenantAssetTypesAsync();
  236 + ListenableFuture<List<TenantAssetType>> tenantAssetTypes = Futures.transform(tenantAssetTypeEntities,
  237 + (Function<List<TenantAssetTypeEntity>, List<TenantAssetType>>) assetTypeEntities -> {
  238 + List<TenantAssetType> assetTypes = new ArrayList<>();
  239 + for (TenantAssetTypeEntity assetTypeEntity : assetTypeEntities) {
  240 + if (assetTypeEntity.getTenantId().equals(tenantId.getId())) {
  241 + assetTypes.add(assetTypeEntity.toTenantAssetType());
  242 + }
  243 + }
  244 + assetTypes.sort((TenantAssetType o1, TenantAssetType o2) -> o1.getType().compareTo(o2.getType()));
  245 + return assetTypes;
  246 + });
  247 + return tenantAssetTypes;
  248 + }
  249 +
210 250 private DataValidator<Asset> assetValidator =
211 251 new DataValidator<Asset>() {
212 252
... ... @@ -232,6 +272,9 @@ public class BaseAssetService extends BaseEntityService implements AssetService
232 272
233 273 @Override
234 274 protected void validateDataImpl(Asset asset) {
  275 + if (StringUtils.isEmpty(asset.getType())) {
  276 + throw new DataValidationException("Asset type should be specified!");
  277 + }
235 278 if (StringUtils.isEmpty(asset.getName())) {
236 279 throw new DataValidationException("Asset name should be specified!");
237 280 }
... ...
... ... @@ -45,7 +45,6 @@ public class ServiceCacheConfiguration {
45 45 @Value("${cache.device_credentials.time_to_live}")
46 46 private Integer cacheDeviceCredentialsTTL;
47 47
48   -
49 48 @Value("${zk.enabled}")
50 49 private boolean zkEnabled;
51 50 @Value("${zk.url}")
... ...
... ... @@ -31,17 +31,15 @@ import com.google.common.util.concurrent.ListenableFuture;
31 31 import lombok.extern.slf4j.Slf4j;
32 32 import org.apache.commons.lang3.StringUtils;
33 33 import org.thingsboard.server.common.data.Customer;
34   -import org.thingsboard.server.common.data.asset.Asset;
35 34 import org.thingsboard.server.common.data.id.CustomerId;
36 35 import org.thingsboard.server.common.data.id.TenantId;
37 36 import org.thingsboard.server.common.data.page.TextPageData;
38 37 import org.thingsboard.server.common.data.page.TextPageLink;
39 38 import org.thingsboard.server.dao.dashboard.DashboardService;
40 39 import org.thingsboard.server.dao.device.DeviceService;
41   -import org.thingsboard.server.dao.entity.BaseEntityService;
  40 +import org.thingsboard.server.dao.entity.AbstractEntityService;
42 41 import org.thingsboard.server.dao.exception.DataValidationException;
43 42 import org.thingsboard.server.dao.exception.IncorrectParameterException;
44   -import org.thingsboard.server.dao.model.AssetEntity;
45 43 import org.thingsboard.server.dao.model.CustomerEntity;
46 44 import org.thingsboard.server.dao.model.TenantEntity;
47 45 import org.thingsboard.server.dao.service.DataValidator;
... ... @@ -53,7 +51,7 @@ import org.springframework.stereotype.Service;
53 51 import org.thingsboard.server.dao.service.Validator;
54 52 @Service
55 53 @Slf4j
56   -public class CustomerServiceImpl extends BaseEntityService implements CustomerService {
  54 +public class CustomerServiceImpl extends AbstractEntityService implements CustomerService {
57 55
58 56 private static final String PUBLIC_CUSTOMER_TITLE = "Public";
59 57
... ...
... ... @@ -15,6 +15,7 @@
15 15 */
16 16 package org.thingsboard.server.dao.dashboard;
17 17
  18 +import com.google.common.util.concurrent.ListenableFuture;
18 19 import org.thingsboard.server.common.data.Dashboard;
19 20 import org.thingsboard.server.common.data.DashboardInfo;
20 21 import org.thingsboard.server.common.data.id.CustomerId;
... ... @@ -27,8 +28,12 @@ public interface DashboardService {
27 28
28 29 public Dashboard findDashboardById(DashboardId dashboardId);
29 30
  31 + public ListenableFuture<Dashboard> findDashboardByIdAsync(DashboardId dashboardId);
  32 +
30 33 public DashboardInfo findDashboardInfoById(DashboardId dashboardId);
31 34
  35 + public ListenableFuture<DashboardInfo> findDashboardInfoByIdAsync(DashboardId dashboardId);
  36 +
32 37 public Dashboard saveDashboard(Dashboard dashboard);
33 38
34 39 public Dashboard assignDashboardToCustomer(DashboardId dashboardId, CustomerId customerId);
... ...
... ... @@ -17,9 +17,13 @@ package org.thingsboard.server.dao.dashboard;
17 17
18 18 import static org.thingsboard.server.dao.DaoUtil.convertDataList;
19 19 import static org.thingsboard.server.dao.DaoUtil.getData;
  20 +import static org.thingsboard.server.dao.service.Validator.validateId;
20 21
21 22 import java.util.List;
22 23
  24 +import com.google.common.base.Function;
  25 +import com.google.common.util.concurrent.Futures;
  26 +import com.google.common.util.concurrent.ListenableFuture;
23 27 import lombok.extern.slf4j.Slf4j;
24 28 import org.apache.commons.lang3.StringUtils;
25 29 import org.thingsboard.server.common.data.Dashboard;
... ... @@ -30,7 +34,7 @@ import org.thingsboard.server.common.data.id.TenantId;
30 34 import org.thingsboard.server.common.data.page.TextPageData;
31 35 import org.thingsboard.server.common.data.page.TextPageLink;
32 36 import org.thingsboard.server.dao.customer.CustomerDao;
33   -import org.thingsboard.server.dao.entity.BaseEntityService;
  37 +import org.thingsboard.server.dao.entity.AbstractEntityService;
34 38 import org.thingsboard.server.dao.exception.DataValidationException;
35 39 import org.thingsboard.server.dao.model.*;
36 40 import org.thingsboard.server.dao.service.DataValidator;
... ... @@ -42,7 +46,7 @@ import org.thingsboard.server.dao.service.Validator;
42 46
43 47 @Service
44 48 @Slf4j
45   -public class DashboardServiceImpl extends BaseEntityService implements DashboardService {
  49 +public class DashboardServiceImpl extends AbstractEntityService implements DashboardService {
46 50
47 51 @Autowired
48 52 private DashboardDao dashboardDao;
... ... @@ -65,6 +69,14 @@ public class DashboardServiceImpl extends BaseEntityService implements Dashboard
65 69 }
66 70
67 71 @Override
  72 + public ListenableFuture<Dashboard> findDashboardByIdAsync(DashboardId dashboardId) {
  73 + log.trace("Executing findDashboardByIdAsync [{}]", dashboardId);
  74 + validateId(dashboardId, "Incorrect dashboardId " + dashboardId);
  75 + ListenableFuture<DashboardEntity> dashboardEntity = dashboardDao.findByIdAsync(dashboardId.getId());
  76 + return Futures.transform(dashboardEntity, (Function<? super DashboardEntity, ? extends Dashboard>) input -> getData(input));
  77 + }
  78 +
  79 + @Override
68 80 public DashboardInfo findDashboardInfoById(DashboardId dashboardId) {
69 81 log.trace("Executing findDashboardInfoById [{}]", dashboardId);
70 82 Validator.validateId(dashboardId, "Incorrect dashboardId " + dashboardId);
... ... @@ -73,6 +85,14 @@ public class DashboardServiceImpl extends BaseEntityService implements Dashboard
73 85 }
74 86
75 87 @Override
  88 + public ListenableFuture<DashboardInfo> findDashboardInfoByIdAsync(DashboardId dashboardId) {
  89 + log.trace("Executing findDashboardInfoByIdAsync [{}]", dashboardId);
  90 + validateId(dashboardId, "Incorrect dashboardId " + dashboardId);
  91 + ListenableFuture<DashboardInfoEntity> dashboardInfoEntity = dashboardInfoDao.findByIdAsync(dashboardId.getId());
  92 + return Futures.transform(dashboardInfoEntity, (Function<? super DashboardInfoEntity, ? extends DashboardInfo>) input -> getData(input));
  93 + }
  94 +
  95 + @Override
76 96 public Dashboard saveDashboard(Dashboard dashboard) {
77 97 log.trace("Executing saveDashboard [{}]", dashboard);
78 98 dashboardValidator.validate(dashboard);
... ...
... ... @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.Device;
24 24 import org.thingsboard.server.common.data.page.TextPageLink;
25 25 import org.thingsboard.server.dao.Dao;
26 26 import org.thingsboard.server.dao.model.DeviceEntity;
  27 +import org.thingsboard.server.dao.model.TenantDeviceTypeEntity;
27 28
28 29 /**
29 30 * The Interface DeviceDao.
... ... @@ -49,6 +50,16 @@ public interface DeviceDao extends Dao<DeviceEntity> {
49 50 List<DeviceEntity> findDevicesByTenantId(UUID tenantId, TextPageLink pageLink);
50 51
51 52 /**
  53 + * Find devices by tenantId, type and page link.
  54 + *
  55 + * @param tenantId the tenantId
  56 + * @param type the type
  57 + * @param pageLink the page link
  58 + * @return the list of device objects
  59 + */
  60 + List<DeviceEntity> findDevicesByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink);
  61 +
  62 + /**
52 63 * Find devices by tenantId and devices Ids.
53 64 *
54 65 * @param tenantId the tenantId
... ... @@ -68,6 +79,18 @@ public interface DeviceDao extends Dao<DeviceEntity> {
68 79 List<DeviceEntity> findDevicesByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink);
69 80
70 81 /**
  82 + * Find devices by tenantId, customerId, type and page link.
  83 + *
  84 + * @param tenantId the tenantId
  85 + * @param customerId the customerId
  86 + * @param type the type
  87 + * @param pageLink the page link
  88 + * @return the list of device objects
  89 + */
  90 + List<DeviceEntity> findDevicesByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink);
  91 +
  92 +
  93 + /**
71 94 * Find devices by tenantId, customerId and devices Ids.
72 95 *
73 96 * @param tenantId the tenantId
... ... @@ -85,4 +108,11 @@ public interface DeviceDao extends Dao<DeviceEntity> {
85 108 * @return the optional device object
86 109 */
87 110 Optional<DeviceEntity> findDevicesByTenantIdAndName(UUID tenantId, String name);
  111 +
  112 + /**
  113 + * Find tenants device types.
  114 + *
  115 + * @return the list of tenant device type objects
  116 + */
  117 + ListenableFuture<List<TenantDeviceTypeEntity>> findTenantDeviceTypesAsync();
88 118 }
... ...
... ... @@ -22,7 +22,12 @@ import static org.thingsboard.server.dao.model.ModelConstants.*;
22 22
23 23 import java.util.*;
24 24
  25 +import com.datastax.driver.core.ResultSet;
  26 +import com.datastax.driver.core.ResultSetFuture;
25 27 import com.datastax.driver.core.querybuilder.Select;
  28 +import com.datastax.driver.mapping.Result;
  29 +import com.google.common.base.Function;
  30 +import com.google.common.util.concurrent.Futures;
26 31 import com.google.common.util.concurrent.ListenableFuture;
27 32 import lombok.extern.slf4j.Slf4j;
28 33 import org.springframework.stereotype.Component;
... ... @@ -32,6 +37,9 @@ import org.thingsboard.server.dao.AbstractSearchTextDao;
32 37 import org.thingsboard.server.dao.model.DeviceEntity;
33 38 import org.slf4j.Logger;
34 39 import org.slf4j.LoggerFactory;
  40 +import org.thingsboard.server.dao.model.TenantDeviceTypeEntity;
  41 +
  42 +import javax.annotation.Nullable;
35 43
36 44 @Component
37 45 @Slf4j
... ... @@ -64,6 +72,16 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement
64 72 }
65 73
66 74 @Override
  75 + public List<DeviceEntity> findDevicesByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink) {
  76 + log.debug("Try to find devices by tenantId [{}], type [{}] and pageLink [{}]", tenantId, type, pageLink);
  77 + List<DeviceEntity> deviceEntities = findPageWithTextSearch(DEVICE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
  78 + Arrays.asList(eq(DEVICE_TYPE_PROPERTY, type),
  79 + eq(DEVICE_TENANT_ID_PROPERTY, tenantId)), pageLink);
  80 + log.trace("Found devices [{}] by tenantId [{}], type [{}] and pageLink [{}]", deviceEntities, tenantId, type, pageLink);
  81 + return deviceEntities;
  82 + }
  83 +
  84 + @Override
67 85 public ListenableFuture<List<DeviceEntity>> findDevicesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> deviceIds) {
68 86 log.debug("Try to find devices by tenantId [{}] and device Ids [{}]", tenantId, deviceIds);
69 87 Select select = select().from(getColumnFamilyName());
... ... @@ -75,7 +93,7 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement
75 93
76 94 @Override
77 95 public List<DeviceEntity> findDevicesByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) {
78   - log.debug("Try to find devices by tenantId [{}], customerId[{}] and pageLink [{}]", tenantId, customerId, pageLink);
  96 + log.debug("Try to find devices by tenantId [{}], customerId [{}] and pageLink [{}]", tenantId, customerId, pageLink);
79 97 List<DeviceEntity> deviceEntities = findPageWithTextSearch(DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
80 98 Arrays.asList(eq(DEVICE_CUSTOMER_ID_PROPERTY, customerId),
81 99 eq(DEVICE_TENANT_ID_PROPERTY, tenantId)),
... ... @@ -86,6 +104,19 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement
86 104 }
87 105
88 106 @Override
  107 + public List<DeviceEntity> findDevicesByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink) {
  108 + log.debug("Try to find devices by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", tenantId, customerId, type, pageLink);
  109 + List<DeviceEntity> deviceEntities = findPageWithTextSearch(DEVICE_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
  110 + Arrays.asList(eq(DEVICE_TYPE_PROPERTY, type),
  111 + eq(DEVICE_CUSTOMER_ID_PROPERTY, customerId),
  112 + eq(DEVICE_TENANT_ID_PROPERTY, tenantId)),
  113 + pageLink);
  114 +
  115 + log.trace("Found devices [{}] by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", deviceEntities, tenantId, customerId, type, pageLink);
  116 + return deviceEntities;
  117 + }
  118 +
  119 + @Override
89 120 public ListenableFuture<List<DeviceEntity>> findDevicesByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> deviceIds) {
90 121 log.debug("Try to find devices by tenantId [{}], customerId [{}] and device Ids [{}]", tenantId, customerId, deviceIds);
91 122 Select select = select().from(getColumnFamilyName());
... ... @@ -105,4 +136,24 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement
105 136 return Optional.ofNullable(findOneByStatement(query));
106 137 }
107 138
  139 + @Override
  140 + public ListenableFuture<List<TenantDeviceTypeEntity>> findTenantDeviceTypesAsync() {
  141 + Select statement = select().distinct().column(DEVICE_TYPE_PROPERTY).column(DEVICE_TENANT_ID_PROPERTY).from(DEVICE_TYPES_BY_TENANT_VIEW_NAME);
  142 + statement.setConsistencyLevel(cluster.getDefaultReadConsistencyLevel());
  143 + ResultSetFuture resultSetFuture = getSession().executeAsync(statement);
  144 + ListenableFuture<List<TenantDeviceTypeEntity>> result = Futures.transform(resultSetFuture, new Function<ResultSet, List<TenantDeviceTypeEntity>>() {
  145 + @Nullable
  146 + @Override
  147 + public List<TenantDeviceTypeEntity> apply(@Nullable ResultSet resultSet) {
  148 + Result<TenantDeviceTypeEntity> result = cluster.getMapper(TenantDeviceTypeEntity.class).map(resultSet);
  149 + if (result != null) {
  150 + return result.all();
  151 + } else {
  152 + return Collections.emptyList();
  153 + }
  154 + }
  155 + });
  156 + return result;
  157 + }
  158 +
108 159 }
... ...
... ... @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.device;
17 17
18 18 import com.google.common.util.concurrent.ListenableFuture;
19 19 import org.thingsboard.server.common.data.Device;
  20 +import org.thingsboard.server.common.data.TenantDeviceType;
20 21 import org.thingsboard.server.common.data.id.CustomerId;
21 22 import org.thingsboard.server.common.data.id.DeviceId;
22 23 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -44,16 +45,22 @@ public interface DeviceService {
44 45
45 46 TextPageData<Device> findDevicesByTenantId(TenantId tenantId, TextPageLink pageLink);
46 47
  48 + TextPageData<Device> findDevicesByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink);
  49 +
47 50 ListenableFuture<List<Device>> findDevicesByTenantIdAndIdsAsync(TenantId tenantId, List<DeviceId> deviceIds);
48 51
49 52 void deleteDevicesByTenantId(TenantId tenantId);
50 53
51 54 TextPageData<Device> findDevicesByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink);
52 55
  56 + TextPageData<Device> findDevicesByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, TextPageLink pageLink);
  57 +
53 58 ListenableFuture<List<Device>> findDevicesByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<DeviceId> deviceIds);
54 59
55 60 void unassignCustomerDevices(TenantId tenantId, CustomerId customerId);
56 61
57 62 ListenableFuture<List<Device>> findDevicesByQuery(DeviceSearchQuery query);
58 63
  64 + ListenableFuture<List<TenantDeviceType>> findDeviceTypesByTenantId(TenantId tenantId);
  65 +
59 66 }
... ...
... ... @@ -26,6 +26,7 @@ import org.springframework.stereotype.Service;
26 26 import org.springframework.util.StringUtils;
27 27 import org.thingsboard.server.common.data.Device;
28 28 import org.thingsboard.server.common.data.EntityType;
  29 +import org.thingsboard.server.common.data.TenantDeviceType;
29 30 import org.thingsboard.server.common.data.id.CustomerId;
30 31 import org.thingsboard.server.common.data.id.DeviceId;
31 32 import org.thingsboard.server.common.data.id.EntityId;
... ... @@ -36,10 +37,11 @@ import org.thingsboard.server.common.data.relation.EntityRelation;
36 37 import org.thingsboard.server.common.data.security.DeviceCredentials;
37 38 import org.thingsboard.server.common.data.security.DeviceCredentialsType;
38 39 import org.thingsboard.server.dao.customer.CustomerDao;
39   -import org.thingsboard.server.dao.entity.BaseEntityService;
  40 +import org.thingsboard.server.dao.entity.AbstractEntityService;
40 41 import org.thingsboard.server.dao.exception.DataValidationException;
41 42 import org.thingsboard.server.dao.model.CustomerEntity;
42 43 import org.thingsboard.server.dao.model.DeviceEntity;
  44 +import org.thingsboard.server.dao.model.TenantDeviceTypeEntity;
43 45 import org.thingsboard.server.dao.model.TenantEntity;
44 46 import org.thingsboard.server.dao.relation.EntitySearchDirection;
45 47 import org.thingsboard.server.dao.service.DataValidator;
... ... @@ -47,9 +49,7 @@ import org.thingsboard.server.dao.service.PaginatedRemover;
47 49 import org.thingsboard.server.dao.tenant.TenantDao;
48 50
49 51 import javax.annotation.Nullable;
50   -import java.util.ArrayList;
51   -import java.util.List;
52   -import java.util.Optional;
  52 +import java.util.*;
53 53 import java.util.stream.Collectors;
54 54
55 55 import static org.thingsboard.server.dao.DaoUtil.*;
... ... @@ -58,7 +58,7 @@ import static org.thingsboard.server.dao.service.Validator.*;
58 58
59 59 @Service
60 60 @Slf4j
61   -public class DeviceServiceImpl extends BaseEntityService implements DeviceService {
  61 +public class DeviceServiceImpl extends AbstractEntityService implements DeviceService {
62 62
63 63 @Autowired
64 64 private DeviceDao deviceDao;
... ... @@ -148,7 +148,18 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic
148 148 validatePageLink(pageLink, "Incorrect page link " + pageLink);
149 149 List<DeviceEntity> deviceEntities = deviceDao.findDevicesByTenantId(tenantId.getId(), pageLink);
150 150 List<Device> devices = convertDataList(deviceEntities);
151   - return new TextPageData<Device>(devices, pageLink);
  151 + return new TextPageData<>(devices, pageLink);
  152 + }
  153 +
  154 + @Override
  155 + public TextPageData<Device> findDevicesByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink) {
  156 + log.trace("Executing findDevicesByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink);
  157 + validateId(tenantId, "Incorrect tenantId " + tenantId);
  158 + validateString(type, "Incorrect type " + type);
  159 + validatePageLink(pageLink, "Incorrect page link " + pageLink);
  160 + List<DeviceEntity> deviceEntities = deviceDao.findDevicesByTenantIdAndType(tenantId.getId(), type, pageLink);
  161 + List<Device> devices = convertDataList(deviceEntities);
  162 + return new TextPageData<>(devices, pageLink);
152 163 }
153 164
154 165 @Override
... ... @@ -176,7 +187,19 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic
176 187 validatePageLink(pageLink, "Incorrect page link " + pageLink);
177 188 List<DeviceEntity> deviceEntities = deviceDao.findDevicesByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink);
178 189 List<Device> devices = convertDataList(deviceEntities);
179   - return new TextPageData<Device>(devices, pageLink);
  190 + return new TextPageData<>(devices, pageLink);
  191 + }
  192 +
  193 + @Override
  194 + public TextPageData<Device> findDevicesByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, TextPageLink pageLink) {
  195 + log.trace("Executing findDevicesByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}], type [{}], pageLink [{}]", tenantId, customerId, type, pageLink);
  196 + validateId(tenantId, "Incorrect tenantId " + tenantId);
  197 + validateId(customerId, "Incorrect customerId " + customerId);
  198 + validateString(type, "Incorrect type " + type);
  199 + validatePageLink(pageLink, "Incorrect page link " + pageLink);
  200 + List<DeviceEntity> deviceEntities = deviceDao.findDevicesByTenantIdAndCustomerIdAndType(tenantId.getId(), customerId.getId(), type, pageLink);
  201 + List<Device> devices = convertDataList(deviceEntities);
  202 + return new TextPageData<>(devices, pageLink);
180 203 }
181 204
182 205 @Override
... ... @@ -224,6 +247,25 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic
224 247 return devices;
225 248 }
226 249
  250 + @Override
  251 + public ListenableFuture<List<TenantDeviceType>> findDeviceTypesByTenantId(TenantId tenantId) {
  252 + log.trace("Executing findDeviceTypesByTenantId, tenantId [{}]", tenantId);
  253 + validateId(tenantId, "Incorrect tenantId " + tenantId);
  254 + ListenableFuture<List<TenantDeviceTypeEntity>> tenantDeviceTypeEntities = deviceDao.findTenantDeviceTypesAsync();
  255 + ListenableFuture<List<TenantDeviceType>> tenantDeviceTypes = Futures.transform(tenantDeviceTypeEntities,
  256 + (Function<List<TenantDeviceTypeEntity>, List<TenantDeviceType>>) deviceTypeEntities -> {
  257 + List<TenantDeviceType> deviceTypes = new ArrayList<>();
  258 + for (TenantDeviceTypeEntity deviceTypeEntity : deviceTypeEntities) {
  259 + if (deviceTypeEntity.getTenantId().equals(tenantId.getId())) {
  260 + deviceTypes.add(deviceTypeEntity.toTenantDeviceType());
  261 + }
  262 + }
  263 + deviceTypes.sort((TenantDeviceType o1, TenantDeviceType o2) -> o1.getType().compareTo(o2.getType()));
  264 + return deviceTypes;
  265 + });
  266 + return tenantDeviceTypes;
  267 + }
  268 +
227 269 private DataValidator<Device> deviceValidator =
228 270 new DataValidator<Device>() {
229 271
... ... @@ -249,6 +291,9 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic
249 291
250 292 @Override
251 293 protected void validateDataImpl(Device device) {
  294 + if (StringUtils.isEmpty(device.getType())) {
  295 + throw new DataValidationException("Device type should be specified!");
  296 + }
252 297 if (StringUtils.isEmpty(device.getName())) {
253 298 throw new DataValidationException("Device name should be specified!");
254 299 }
... ...
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package org.thingsboard.server.dao.entity;
  18 +
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.springframework.beans.factory.annotation.Autowired;
  21 +import org.thingsboard.server.common.data.id.EntityId;
  22 +import org.thingsboard.server.dao.relation.RelationService;
  23 +
  24 +@Slf4j
  25 +public abstract class AbstractEntityService {
  26 +
  27 + @Autowired
  28 + protected RelationService relationService;
  29 +
  30 + protected void deleteEntityRelations(EntityId entityId) {
  31 + log.trace("Executing deleteEntityRelations [{}]", entityId);
  32 + relationService.deleteEntityRelations(entityId);
  33 + }
  34 +
  35 +
  36 +}
... ...
... ... @@ -15,23 +15,102 @@
15 15 */
16 16 package org.thingsboard.server.dao.entity;
17 17
  18 +import com.google.common.base.Function;
  19 +import com.google.common.util.concurrent.Futures;
  20 +import com.google.common.util.concurrent.ListenableFuture;
18 21 import lombok.extern.slf4j.Slf4j;
19 22 import org.springframework.beans.factory.annotation.Autowired;
20   -import org.thingsboard.server.common.data.id.EntityId;
21   -import org.thingsboard.server.dao.relation.RelationService;
  23 +import org.springframework.stereotype.Service;
  24 +import org.thingsboard.server.common.data.*;
  25 +import org.thingsboard.server.common.data.alarm.AlarmId;
  26 +import org.thingsboard.server.common.data.id.*;
  27 +import org.thingsboard.server.dao.alarm.AlarmService;
  28 +import org.thingsboard.server.dao.asset.AssetService;
  29 +import org.thingsboard.server.dao.customer.CustomerService;
  30 +import org.thingsboard.server.dao.dashboard.DashboardService;
  31 +import org.thingsboard.server.dao.device.DeviceService;
  32 +import org.thingsboard.server.dao.plugin.PluginService;
  33 +import org.thingsboard.server.dao.rule.RuleService;
  34 +import org.thingsboard.server.dao.tenant.TenantService;
  35 +import org.thingsboard.server.dao.user.UserService;
22 36
23 37 /**
24 38 * Created by ashvayka on 04.05.17.
25 39 */
  40 +@Service
26 41 @Slf4j
27   -public class BaseEntityService {
  42 +public class BaseEntityService extends AbstractEntityService implements EntityService {
28 43
29 44 @Autowired
30   - protected RelationService relationService;
  45 + private AssetService assetService;
31 46
32   - protected void deleteEntityRelations(EntityId entityId) {
33   - log.trace("Executing deleteEntityRelations [{}]", entityId);
34   - relationService.deleteEntityRelations(entityId);
  47 + @Autowired
  48 + private DeviceService deviceService;
  49 +
  50 + @Autowired
  51 + private RuleService ruleService;
  52 +
  53 + @Autowired
  54 + private PluginService pluginService;
  55 +
  56 + @Autowired
  57 + private TenantService tenantService;
  58 +
  59 + @Autowired
  60 + private CustomerService customerService;
  61 +
  62 + @Autowired
  63 + private UserService userService;
  64 +
  65 + @Autowired
  66 + private DashboardService dashboardService;
  67 +
  68 + @Autowired
  69 + private AlarmService alarmService;
  70 +
  71 + @Override
  72 + public void deleteEntityRelations(EntityId entityId) {
  73 + super.deleteEntityRelations(entityId);
  74 + }
  75 +
  76 + @Override
  77 + public ListenableFuture<String> fetchEntityNameAsync(EntityId entityId) {
  78 + log.trace("Executing fetchEntityNameAsync [{}]", entityId);
  79 + ListenableFuture<String> entityName;
  80 + ListenableFuture<? extends HasName> hasName;
  81 + switch (entityId.getEntityType()) {
  82 + case ASSET:
  83 + hasName = assetService.findAssetByIdAsync(new AssetId(entityId.getId()));
  84 + break;
  85 + case DEVICE:
  86 + hasName = deviceService.findDeviceByIdAsync(new DeviceId(entityId.getId()));
  87 + break;
  88 + case RULE:
  89 + hasName = ruleService.findRuleByIdAsync(new RuleId(entityId.getId()));
  90 + break;
  91 + case PLUGIN:
  92 + hasName = pluginService.findPluginByIdAsync(new PluginId(entityId.getId()));
  93 + break;
  94 + case TENANT:
  95 + hasName = tenantService.findTenantByIdAsync(new TenantId(entityId.getId()));
  96 + break;
  97 + case CUSTOMER:
  98 + hasName = customerService.findCustomerByIdAsync(new CustomerId(entityId.getId()));
  99 + break;
  100 + case USER:
  101 + hasName = userService.findUserByIdAsync(new UserId(entityId.getId()));
  102 + break;
  103 + case DASHBOARD:
  104 + hasName = dashboardService.findDashboardInfoByIdAsync(new DashboardId(entityId.getId()));
  105 + break;
  106 + case ALARM:
  107 + hasName = alarmService.findAlarmByIdAsync(new AlarmId(entityId.getId()));
  108 + break;
  109 + default:
  110 + throw new IllegalStateException("Not Implemented!");
  111 + }
  112 + entityName = Futures.transform(hasName, (Function<HasName, String>) hasName1 -> hasName1.getName() );
  113 + return entityName;
35 114 }
36 115
37 116 }
... ...
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package org.thingsboard.server.dao.entity;
  18 +
  19 +import com.google.common.util.concurrent.ListenableFuture;
  20 +import org.thingsboard.server.common.data.id.EntityId;
  21 +
  22 +public interface EntityService {
  23 +
  24 + ListenableFuture<String> fetchEntityNameAsync(EntityId entityId);
  25 +
  26 + void deleteEntityRelations(EntityId entityId);
  27 +
  28 +}
... ...
... ... @@ -49,12 +49,13 @@ public final class AssetEntity implements SearchTextEntity<Asset> {
49 49 @Column(name = ASSET_CUSTOMER_ID_PROPERTY)
50 50 private UUID customerId;
51 51
52   - @Column(name = ASSET_NAME_PROPERTY)
53   - private String name;
54   -
  52 + @PartitionKey(value = 3)
55 53 @Column(name = ASSET_TYPE_PROPERTY)
56 54 private String type;
57 55
  56 + @Column(name = ASSET_NAME_PROPERTY)
  57 + private String name;
  58 +
58 59 @Column(name = SEARCH_TEXT_PROPERTY)
59 60 private String searchText;
60 61
... ...
... ... @@ -49,12 +49,13 @@ public final class DeviceEntity implements SearchTextEntity<Device> {
49 49 @Column(name = DEVICE_CUSTOMER_ID_PROPERTY)
50 50 private UUID customerId;
51 51
52   - @Column(name = DEVICE_NAME_PROPERTY)
53   - private String name;
54   -
  52 + @PartitionKey(value = 3)
55 53 @Column(name = DEVICE_TYPE_PROPERTY)
56 54 private String type;
57 55
  56 + @Column(name = DEVICE_NAME_PROPERTY)
  57 + private String name;
  58 +
58 59 @Column(name = SEARCH_TEXT_PROPERTY)
59 60 private String searchText;
60 61
... ...
... ... @@ -124,8 +124,11 @@ public class ModelConstants {
124 124 public static final String DEVICE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
125 125
126 126 public static final String DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_and_search_text";
  127 + public static final String DEVICE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_by_type_and_search_text";
127 128 public static final String DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_customer_and_search_text";
  129 + public static final String DEVICE_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_customer_by_type_and_search_text";
128 130 public static final String DEVICE_BY_TENANT_AND_NAME_VIEW_NAME = "device_by_tenant_and_name";
  131 + public static final String DEVICE_TYPES_BY_TENANT_VIEW_NAME = "device_types_by_tenant";
129 132
130 133 /**
131 134 * Cassandra asset constants.
... ... @@ -138,8 +141,11 @@ public class ModelConstants {
138 141 public static final String ASSET_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
139 142
140 143 public static final String ASSET_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_tenant_and_search_text";
  144 + public static final String ASSET_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_tenant_by_type_and_search_text";
141 145 public static final String ASSET_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_customer_and_search_text";
  146 + public static final String ASSET_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_customer_by_type_and_search_text";
142 147 public static final String ASSET_BY_TENANT_AND_NAME_VIEW_NAME = "asset_by_tenant_and_name";
  148 + public static final String ASSET_TYPES_BY_TENANT_VIEW_NAME = "asset_types_by_tenant";
143 149
144 150 /**
145 151 * Cassandra entity relation constants.
... ...
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package org.thingsboard.server.dao.model;
  18 +
  19 +import com.datastax.driver.mapping.annotations.Column;
  20 +import com.datastax.driver.mapping.annotations.PartitionKey;
  21 +import com.datastax.driver.mapping.annotations.Table;
  22 +import com.datastax.driver.mapping.annotations.Transient;
  23 +import org.thingsboard.server.common.data.asset.TenantAssetType;
  24 +import org.thingsboard.server.common.data.id.TenantId;
  25 +
  26 +import java.util.UUID;
  27 +
  28 +import static org.thingsboard.server.dao.model.ModelConstants.*;
  29 +
  30 +@Table(name = ASSET_TYPES_BY_TENANT_VIEW_NAME)
  31 +public class TenantAssetTypeEntity {
  32 +
  33 + @Transient
  34 + private static final long serialVersionUID = -1268181161886910152L;
  35 +
  36 + @PartitionKey(value = 0)
  37 + @Column(name = ASSET_TYPE_PROPERTY)
  38 + private String type;
  39 +
  40 + @PartitionKey(value = 1)
  41 + @Column(name = ASSET_TENANT_ID_PROPERTY)
  42 + private UUID tenantId;
  43 +
  44 + public TenantAssetTypeEntity() {
  45 + super();
  46 + }
  47 +
  48 + public TenantAssetTypeEntity(TenantAssetType tenantAssetType) {
  49 + this.type = tenantAssetType.getType();
  50 + if (tenantAssetType.getTenantId() != null) {
  51 + this.tenantId = tenantAssetType.getTenantId().getId();
  52 + }
  53 + }
  54 +
  55 + public String getType() {
  56 + return type;
  57 + }
  58 +
  59 + public void setType(String type) {
  60 + this.type = type;
  61 + }
  62 +
  63 + public UUID getTenantId() {
  64 + return tenantId;
  65 + }
  66 +
  67 + public void setTenantId(UUID tenantId) {
  68 + this.tenantId = tenantId;
  69 + }
  70 +
  71 + @Override
  72 + public int hashCode() {
  73 + int result = type != null ? type.hashCode() : 0;
  74 + result = 31 * result + (tenantId != null ? tenantId.hashCode() : 0);
  75 + return result;
  76 + }
  77 +
  78 + @Override
  79 + public boolean equals(Object o) {
  80 + if (this == o) return true;
  81 + if (o == null || getClass() != o.getClass()) return false;
  82 +
  83 + TenantAssetTypeEntity that = (TenantAssetTypeEntity) o;
  84 +
  85 + if (type != null ? !type.equals(that.type) : that.type != null) return false;
  86 + return tenantId != null ? tenantId.equals(that.tenantId) : that.tenantId == null;
  87 +
  88 + }
  89 +
  90 + @Override
  91 + public String toString() {
  92 + final StringBuilder sb = new StringBuilder("TenantAssetTypeEntity{");
  93 + sb.append("type='").append(type).append('\'');
  94 + sb.append(", tenantId=").append(tenantId);
  95 + sb.append('}');
  96 + return sb.toString();
  97 + }
  98 +
  99 + public TenantAssetType toTenantAssetType() {
  100 + TenantAssetType tenantAssetType = new TenantAssetType();
  101 + tenantAssetType.setType(type);
  102 + if (tenantId != null) {
  103 + tenantAssetType.setTenantId(new TenantId(tenantId));
  104 + }
  105 + return tenantAssetType;
  106 + }
  107 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package org.thingsboard.server.dao.model;
  18 +
  19 +import com.datastax.driver.mapping.annotations.Column;
  20 +import com.datastax.driver.mapping.annotations.PartitionKey;
  21 +import com.datastax.driver.mapping.annotations.Table;
  22 +import com.datastax.driver.mapping.annotations.Transient;
  23 +import org.thingsboard.server.common.data.TenantDeviceType;
  24 +import org.thingsboard.server.common.data.id.TenantId;
  25 +
  26 +import java.util.UUID;
  27 +
  28 +import static org.thingsboard.server.dao.model.ModelConstants.*;
  29 +
  30 +@Table(name = DEVICE_TYPES_BY_TENANT_VIEW_NAME)
  31 +public class TenantDeviceTypeEntity {
  32 +
  33 + @Transient
  34 + private static final long serialVersionUID = -1268181166886910152L;
  35 +
  36 + @PartitionKey(value = 0)
  37 + @Column(name = DEVICE_TYPE_PROPERTY)
  38 + private String type;
  39 +
  40 + @PartitionKey(value = 1)
  41 + @Column(name = DEVICE_TENANT_ID_PROPERTY)
  42 + private UUID tenantId;
  43 +
  44 + public TenantDeviceTypeEntity() {
  45 + super();
  46 + }
  47 +
  48 + public TenantDeviceTypeEntity(TenantDeviceType tenantDeviceType) {
  49 + this.type = tenantDeviceType.getType();
  50 + if (tenantDeviceType.getTenantId() != null) {
  51 + this.tenantId = tenantDeviceType.getTenantId().getId();
  52 + }
  53 + }
  54 +
  55 + public String getType() {
  56 + return type;
  57 + }
  58 +
  59 + public void setType(String type) {
  60 + this.type = type;
  61 + }
  62 +
  63 + public UUID getTenantId() {
  64 + return tenantId;
  65 + }
  66 +
  67 + public void setTenantId(UUID tenantId) {
  68 + this.tenantId = tenantId;
  69 + }
  70 +
  71 + @Override
  72 + public int hashCode() {
  73 + int result = type != null ? type.hashCode() : 0;
  74 + result = 31 * result + (tenantId != null ? tenantId.hashCode() : 0);
  75 + return result;
  76 + }
  77 +
  78 + @Override
  79 + public boolean equals(Object o) {
  80 + if (this == o) return true;
  81 + if (o == null || getClass() != o.getClass()) return false;
  82 +
  83 + TenantDeviceTypeEntity that = (TenantDeviceTypeEntity) o;
  84 +
  85 + if (type != null ? !type.equals(that.type) : that.type != null) return false;
  86 + return tenantId != null ? tenantId.equals(that.tenantId) : that.tenantId == null;
  87 +
  88 + }
  89 +
  90 + @Override
  91 + public String toString() {
  92 + final StringBuilder sb = new StringBuilder("TenantDeviceTypeEntity{");
  93 + sb.append("type='").append(type).append('\'');
  94 + sb.append(", tenantId=").append(tenantId);
  95 + sb.append('}');
  96 + return sb.toString();
  97 + }
  98 +
  99 + public TenantDeviceType toTenantDeviceType() {
  100 + TenantDeviceType tenantDeviceType = new TenantDeviceType();
  101 + tenantDeviceType.setType(type);
  102 + if (tenantId != null) {
  103 + tenantDeviceType.setTenantId(new TenantId(tenantId));
  104 + }
  105 + return tenantDeviceType;
  106 + }
  107 +}
... ...
... ... @@ -22,7 +22,6 @@ import org.apache.commons.lang3.StringUtils;
22 22 import org.springframework.beans.factory.annotation.Autowired;
23 23 import org.springframework.stereotype.Service;
24 24 import org.thingsboard.server.common.data.id.PluginId;
25   -import org.thingsboard.server.common.data.id.RuleId;
26 25 import org.thingsboard.server.common.data.id.TenantId;
27 26 import org.thingsboard.server.common.data.page.TextPageData;
28 27 import org.thingsboard.server.common.data.page.TextPageLink;
... ... @@ -30,9 +29,8 @@ import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
30 29 import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
31 30 import org.thingsboard.server.common.data.plugin.ComponentType;
32 31 import org.thingsboard.server.common.data.plugin.PluginMetaData;
33   -import org.thingsboard.server.common.data.rule.RuleMetaData;
34 32 import org.thingsboard.server.dao.component.ComponentDescriptorService;
35   -import org.thingsboard.server.dao.entity.BaseEntityService;
  33 +import org.thingsboard.server.dao.entity.AbstractEntityService;
36 34 import org.thingsboard.server.dao.exception.DataValidationException;
37 35 import org.thingsboard.server.dao.exception.DatabaseException;
38 36 import org.thingsboard.server.dao.exception.IncorrectParameterException;
... ... @@ -55,7 +53,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId;
55 53
56 54 @Service
57 55 @Slf4j
58   -public class BasePluginService extends BaseEntityService implements PluginService {
  56 +public class BasePluginService extends AbstractEntityService implements PluginService {
59 57
60 58 //TODO: move to a better place.
61 59 public static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID);
... ...
... ... @@ -23,9 +23,24 @@ import lombok.extern.slf4j.Slf4j;
23 23 import org.springframework.beans.factory.annotation.Autowired;
24 24 import org.springframework.stereotype.Service;
25 25 import org.springframework.util.StringUtils;
  26 +import org.thingsboard.server.common.data.BaseData;
  27 +import org.thingsboard.server.common.data.Device;
  28 +import org.thingsboard.server.common.data.EntityType;
  29 +import org.thingsboard.server.common.data.asset.Asset;
  30 +import org.thingsboard.server.common.data.id.AssetId;
  31 +import org.thingsboard.server.common.data.id.DeviceId;
26 32 import org.thingsboard.server.common.data.id.EntityId;
  33 +import org.thingsboard.server.common.data.id.UUIDBased;
27 34 import org.thingsboard.server.common.data.relation.EntityRelation;
  35 +import org.thingsboard.server.common.data.relation.EntityRelationInfo;
  36 +import org.thingsboard.server.dao.asset.AssetService;
  37 +import org.thingsboard.server.dao.customer.CustomerService;
  38 +import org.thingsboard.server.dao.device.DeviceService;
  39 +import org.thingsboard.server.dao.entity.EntityService;
28 40 import org.thingsboard.server.dao.exception.DataValidationException;
  41 +import org.thingsboard.server.dao.plugin.PluginService;
  42 +import org.thingsboard.server.dao.rule.RuleService;
  43 +import org.thingsboard.server.dao.tenant.TenantService;
29 44
30 45 import javax.annotation.Nullable;
31 46 import java.util.*;
... ... @@ -41,6 +56,9 @@ public class BaseRelationService implements RelationService {
41 56 @Autowired
42 57 private RelationDao relationDao;
43 58
  59 + @Autowired
  60 + private EntityService entityService;
  61 +
44 62 @Override
45 63 public ListenableFuture<Boolean> checkRelation(EntityId from, EntityId to, String relationType) {
46 64 log.trace("Executing checkRelation [{}][{}][{}]", from, to, relationType);
... ... @@ -100,6 +118,31 @@ public class BaseRelationService implements RelationService {
100 118 }
101 119
102 120 @Override
  121 + public ListenableFuture<List<EntityRelationInfo>> findInfoByFrom(EntityId from) {
  122 + log.trace("Executing findInfoByFrom [{}]", from);
  123 + validate(from);
  124 + ListenableFuture<List<EntityRelation>> relations = relationDao.findAllByFrom(from);
  125 + ListenableFuture<List<EntityRelationInfo>> relationsInfo = Futures.transform(relations,
  126 + (AsyncFunction<List<EntityRelation>, List<EntityRelationInfo>>) relations1 -> {
  127 + List<ListenableFuture<EntityRelationInfo>> futures = new ArrayList<>();
  128 + relations1.stream().forEach(relation -> futures.add(fetchRelationInfoAsync(relation)));
  129 + return Futures.successfulAsList(futures);
  130 + });
  131 + return relationsInfo;
  132 + }
  133 +
  134 + private ListenableFuture<EntityRelationInfo> fetchRelationInfoAsync(EntityRelation relation) {
  135 + ListenableFuture<String> entityName = entityService.fetchEntityNameAsync(relation.getTo());
  136 + ListenableFuture<EntityRelationInfo> entityRelationInfo =
  137 + Futures.transform(entityName, (Function<String, EntityRelationInfo>) entityName1 -> {
  138 + EntityRelationInfo entityRelationInfo1 = new EntityRelationInfo(relation);
  139 + entityRelationInfo1.setToName(entityName1);
  140 + return entityRelationInfo1;
  141 + });
  142 + return entityRelationInfo;
  143 + }
  144 +
  145 + @Override
103 146 public ListenableFuture<List<EntityRelation>> findByFromAndType(EntityId from, String relationType) {
104 147 log.trace("Executing findByFromAndType [{}][{}]", from, relationType);
105 148 validate(from);
... ...
... ... @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.relation;
18 18 import com.google.common.util.concurrent.ListenableFuture;
19 19 import org.thingsboard.server.common.data.id.EntityId;
20 20 import org.thingsboard.server.common.data.relation.EntityRelation;
  21 +import org.thingsboard.server.common.data.relation.EntityRelationInfo;
21 22
22 23 import java.util.List;
23 24
... ... @@ -38,6 +39,8 @@ public interface RelationService {
38 39
39 40 ListenableFuture<List<EntityRelation>> findByFrom(EntityId from);
40 41
  42 + ListenableFuture<List<EntityRelationInfo>> findInfoByFrom(EntityId from);
  43 +
41 44 ListenableFuture<List<EntityRelation>> findByFromAndType(EntityId from, String relationType);
42 45
43 46 ListenableFuture<List<EntityRelation>> findByTo(EntityId to);
... ...
... ... @@ -23,7 +23,6 @@ import lombok.extern.slf4j.Slf4j;
23 23 import org.apache.commons.lang3.StringUtils;
24 24 import org.springframework.beans.factory.annotation.Autowired;
25 25 import org.springframework.stereotype.Service;
26   -import org.thingsboard.server.common.data.asset.Asset;
27 26 import org.thingsboard.server.common.data.id.RuleId;
28 27 import org.thingsboard.server.common.data.id.TenantId;
29 28 import org.thingsboard.server.common.data.page.TextPageData;
... ... @@ -34,11 +33,10 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
34 33 import org.thingsboard.server.common.data.plugin.PluginMetaData;
35 34 import org.thingsboard.server.common.data.rule.RuleMetaData;
36 35 import org.thingsboard.server.dao.component.ComponentDescriptorService;
37   -import org.thingsboard.server.dao.entity.BaseEntityService;
  36 +import org.thingsboard.server.dao.entity.AbstractEntityService;
38 37 import org.thingsboard.server.dao.exception.DataValidationException;
39 38 import org.thingsboard.server.dao.exception.DatabaseException;
40 39 import org.thingsboard.server.dao.exception.IncorrectParameterException;
41   -import org.thingsboard.server.dao.model.AssetEntity;
42 40 import org.thingsboard.server.dao.model.RuleMetaDataEntity;
43 41 import org.thingsboard.server.dao.plugin.PluginService;
44 42 import org.thingsboard.server.dao.service.DataValidator;
... ... @@ -58,7 +56,7 @@ import static org.thingsboard.server.dao.service.Validator.validatePageLink;
58 56
59 57 @Service
60 58 @Slf4j
61   -public class BaseRuleService extends BaseEntityService implements RuleService {
  59 +public class BaseRuleService extends AbstractEntityService implements RuleService {
62 60
63 61 private final TenantId systemTenantId = new TenantId(NULL_UUID);
64 62
... ...
... ... @@ -26,7 +26,6 @@ import com.google.common.util.concurrent.Futures;
26 26 import com.google.common.util.concurrent.ListenableFuture;
27 27 import lombok.extern.slf4j.Slf4j;
28 28 import org.apache.commons.lang3.StringUtils;
29   -import org.thingsboard.server.common.data.Customer;
30 29 import org.thingsboard.server.common.data.Tenant;
31 30 import org.thingsboard.server.common.data.id.TenantId;
32 31 import org.thingsboard.server.common.data.page.TextPageData;
... ... @@ -34,9 +33,8 @@ import org.thingsboard.server.common.data.page.TextPageLink;
34 33 import org.thingsboard.server.dao.customer.CustomerService;
35 34 import org.thingsboard.server.dao.dashboard.DashboardService;
36 35 import org.thingsboard.server.dao.device.DeviceService;
37   -import org.thingsboard.server.dao.entity.BaseEntityService;
  36 +import org.thingsboard.server.dao.entity.AbstractEntityService;
38 37 import org.thingsboard.server.dao.exception.DataValidationException;
39   -import org.thingsboard.server.dao.model.CustomerEntity;
40 38 import org.thingsboard.server.dao.model.TenantEntity;
41 39 import org.thingsboard.server.dao.plugin.PluginService;
42 40 import org.thingsboard.server.dao.rule.RuleService;
... ... @@ -50,7 +48,7 @@ import org.thingsboard.server.dao.widget.WidgetsBundleService;
50 48
51 49 @Service
52 50 @Slf4j
53   -public class TenantServiceImpl extends BaseEntityService implements TenantService {
  51 +public class TenantServiceImpl extends AbstractEntityService implements TenantService {
54 52
55 53 private static final String DEFAULT_TENANT_REGION = "Global";
56 54
... ...
... ... @@ -15,6 +15,7 @@
15 15 */
16 16 package org.thingsboard.server.dao.user;
17 17
  18 +import com.google.common.util.concurrent.ListenableFuture;
18 19 import org.thingsboard.server.common.data.User;
19 20 import org.thingsboard.server.common.data.id.CustomerId;
20 21 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -27,6 +28,8 @@ public interface UserService {
27 28
28 29 public User findUserById(UserId userId);
29 30
  31 + public ListenableFuture<User> findUserByIdAsync(UserId userId);
  32 +
30 33 public User findUserByEmail(String email);
31 34
32 35 public User saveUser(User user);
... ...
... ... @@ -23,6 +23,9 @@ import static org.thingsboard.server.dao.service.Validator.validateString;
23 23
24 24 import java.util.List;
25 25
  26 +import com.google.common.base.Function;
  27 +import com.google.common.util.concurrent.Futures;
  28 +import com.google.common.util.concurrent.ListenableFuture;
26 29 import lombok.extern.slf4j.Slf4j;
27 30 import org.apache.commons.lang3.RandomStringUtils;
28 31 import org.apache.commons.lang3.StringUtils;
... ... @@ -35,7 +38,7 @@ import org.thingsboard.server.common.data.page.TextPageLink;
35 38 import org.thingsboard.server.common.data.security.Authority;
36 39 import org.thingsboard.server.common.data.security.UserCredentials;
37 40 import org.thingsboard.server.dao.customer.CustomerDao;
38   -import org.thingsboard.server.dao.entity.BaseEntityService;
  41 +import org.thingsboard.server.dao.entity.AbstractEntityService;
39 42 import org.thingsboard.server.dao.exception.DataValidationException;
40 43 import org.thingsboard.server.dao.exception.IncorrectParameterException;
41 44 import org.thingsboard.server.dao.model.*;
... ... @@ -47,7 +50,7 @@ import org.springframework.stereotype.Service;
47 50
48 51 @Service
49 52 @Slf4j
50   -public class UserServiceImpl extends BaseEntityService implements UserService {
  53 +public class UserServiceImpl extends AbstractEntityService implements UserService {
51 54
52 55 @Autowired
53 56 private UserDao userDao;
... ... @@ -78,6 +81,14 @@ public class UserServiceImpl extends BaseEntityService implements UserService {
78 81 }
79 82
80 83 @Override
  84 + public ListenableFuture<User> findUserByIdAsync(UserId userId) {
  85 + log.trace("Executing findUserByIdAsync [{}]", userId);
  86 + validateId(userId, "Incorrect userId " + userId);
  87 + ListenableFuture<UserEntity> userEntity = userDao.findByIdAsync(userId.getId());
  88 + return Futures.transform(userEntity, (Function<? super UserEntity, ? extends User>) input -> getData(input));
  89 + }
  90 +
  91 + @Override
81 92 public User saveUser(User user) {
82 93 log.trace("Executing saveUser [{}]", user);
83 94 userValidator.validate(user);
... ...
... ... @@ -149,66 +149,73 @@ VALUES (
149 149
150 150 /** Demo device **/
151 151
152   -INSERT INTO thingsboard.device ( id, tenant_id, customer_id, name, search_text)
  152 +INSERT INTO thingsboard.device ( id, tenant_id, customer_id, type, name, search_text)
153 153 VALUES (
154 154 minTimeuuid ( '2016-11-01 01:02:05+0000' ),
155 155 minTimeuuid ( '2016-11-01 01:02:01+0000' ),
156 156 minTimeuuid ( '2016-11-01 01:02:03+0000' ),
  157 + 'default',
157 158 'Test Device A1',
158 159 'test device a1'
159 160 );
160 161
161   -INSERT INTO thingsboard.device ( id, tenant_id, customer_id, name, search_text)
  162 +INSERT INTO thingsboard.device ( id, tenant_id, customer_id, type, name, search_text)
162 163 VALUES (
163 164 minTimeuuid ( '2016-11-01 01:02:05+0001' ),
164 165 minTimeuuid ( '2016-11-01 01:02:01+0000' ),
165 166 minTimeuuid ( '2016-11-01 01:02:03+0000' ),
  167 + 'default',
166 168 'Test Device A2',
167 169 'test device a2'
168 170 );
169 171
170   -INSERT INTO thingsboard.device ( id, tenant_id, customer_id, name, search_text)
  172 +INSERT INTO thingsboard.device ( id, tenant_id, customer_id, type, name, search_text)
171 173 VALUES (
172 174 minTimeuuid ( '2016-11-01 01:02:05+0002' ),
173 175 minTimeuuid ( '2016-11-01 01:02:01+0000' ),
174 176 minTimeuuid ( '2016-11-01 01:02:03+0000' ),
  177 + 'default',
175 178 'Test Device A3',
176 179 'test device a3'
177 180 );
178 181
179   -INSERT INTO thingsboard.device ( id, tenant_id, customer_id, name, search_text)
  182 +INSERT INTO thingsboard.device ( id, tenant_id, customer_id, type, name, search_text)
180 183 VALUES (
181 184 minTimeuuid ( '2016-11-01 01:02:05+0003' ),
182 185 minTimeuuid ( '2016-11-01 01:02:01+0000' ),
183 186 minTimeuuid ( '2016-11-01 01:02:03+0001' ),
  187 + 'default',
184 188 'Test Device B1',
185 189 'test device b1'
186 190 );
187 191
188   -INSERT INTO thingsboard.device ( id, tenant_id, customer_id, name, search_text)
  192 +INSERT INTO thingsboard.device ( id, tenant_id, customer_id, type, name, search_text)
189 193 VALUES (
190 194 minTimeuuid ( '2016-11-01 01:02:05+0004' ),
191 195 minTimeuuid ( '2016-11-01 01:02:01+0000' ),
192 196 minTimeuuid ( '2016-11-01 01:02:03+0002' ),
  197 + 'default',
193 198 'Test Device C1',
194 199 'test device c1'
195 200 );
196 201
197   -INSERT INTO thingsboard.device ( id, tenant_id, customer_id, name, search_text, additional_info)
  202 +INSERT INTO thingsboard.device ( id, tenant_id, customer_id, type, name, search_text, additional_info)
198 203 VALUES (
199 204 c8f1a6f0-b993-11e6-8a04-9ff4e1b7933c,
200 205 minTimeuuid ( '2016-11-01 01:02:01+0000' ),
201 206 minTimeuuid ( 0 ),
  207 + 'default',
202 208 'DHT11 Demo Device',
203 209 'dht11 demo device',
204 210 '{"description":"Demo device that is used in sample applications that upload data from DHT11 temperature and humidity sensor"}'
205 211 );
206 212
207   -INSERT INTO thingsboard.device ( id, tenant_id, customer_id, name, search_text, additional_info)
  213 +INSERT INTO thingsboard.device ( id, tenant_id, customer_id, type, name, search_text, additional_info)
208 214 VALUES (
209 215 c8f1a6f0-b993-11e6-8a04-9ff4e1b7933d,
210 216 minTimeuuid ( '2016-11-01 01:02:01+0000' ),
211 217 minTimeuuid ( 0 ),
  218 + 'default',
212 219 'Raspberry Pi Demo Device',
213 220 'raspberry pi demo device',
214 221 '{"description":"Demo device that is used in Raspberry Pi GPIO control sample application"}'
... ...
... ... @@ -152,36 +152,57 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.customer_by_tenant_and_search
152 152 WITH CLUSTERING ORDER BY ( search_text ASC, id DESC );
153 153
154 154 CREATE TABLE IF NOT EXISTS thingsboard.device (
155   - id timeuuid,
156   - tenant_id timeuuid,
157   - customer_id timeuuid,
158   - name text,
159   - type text,
160   - search_text text,
161   - additional_info text,
162   - PRIMARY KEY (id, tenant_id, customer_id)
  155 + id timeuuid,
  156 + tenant_id timeuuid,
  157 + customer_id timeuuid,
  158 + name text,
  159 + type text,
  160 + search_text text,
  161 + additional_info text,
  162 + PRIMARY KEY (id, tenant_id, customer_id, type)
163 163 );
164 164
165 165 CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_tenant_and_name AS
166   - SELECT *
167   - from thingsboard.device
168   - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL
169   - PRIMARY KEY ( tenant_id, name, id, customer_id)
170   - WITH CLUSTERING ORDER BY ( name ASC, id DESC, customer_id DESC);
  166 + SELECT *
  167 + from thingsboard.device
  168 + 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
  169 + PRIMARY KEY ( tenant_id, name, id, customer_id, type)
  170 + WITH CLUSTERING ORDER BY ( name ASC, id DESC, customer_id DESC);
171 171
172 172 CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_tenant_and_search_text AS
173   - SELECT *
174   - from thingsboard.device
175   - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL
176   - PRIMARY KEY ( tenant_id, search_text, id, customer_id)
177   - WITH CLUSTERING ORDER BY ( search_text ASC, id DESC, customer_id DESC);
  173 + SELECT *
  174 + from thingsboard.device
  175 + 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
  176 + PRIMARY KEY ( tenant_id, search_text, id, customer_id, type)
  177 + WITH CLUSTERING ORDER BY ( search_text ASC, id DESC, customer_id DESC);
  178 +
  179 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_tenant_by_type_and_search_text AS
  180 + SELECT *
  181 + from thingsboard.device
  182 + 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
  183 + PRIMARY KEY ( tenant_id, type, search_text, id, customer_id)
  184 + WITH CLUSTERING ORDER BY ( type ASC, search_text ASC, id DESC, customer_id DESC);
178 185
179 186 CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_customer_and_search_text AS
180   - SELECT *
181   - from thingsboard.device
182   - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL
183   - PRIMARY KEY ( customer_id, tenant_id, search_text, id )
184   - WITH CLUSTERING ORDER BY ( tenant_id DESC, search_text ASC, id DESC );
  187 + SELECT *
  188 + from thingsboard.device
  189 + 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
  190 + PRIMARY KEY ( customer_id, tenant_id, search_text, id, type )
  191 + WITH CLUSTERING ORDER BY ( tenant_id DESC, search_text ASC, id DESC );
  192 +
  193 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_customer_by_type_and_search_text AS
  194 + SELECT *
  195 + from thingsboard.device
  196 + 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
  197 + PRIMARY KEY ( customer_id, tenant_id, type, search_text, id )
  198 + WITH CLUSTERING ORDER BY ( tenant_id DESC, type ASC, search_text ASC, id DESC );
  199 +
  200 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_types_by_tenant AS
  201 + SELECT *
  202 + from thingsboard.device
  203 + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND id IS NOT NULL
  204 + PRIMARY KEY ( (type, tenant_id), id, customer_id)
  205 + WITH CLUSTERING ORDER BY ( id ASC, customer_id DESC);
185 206
186 207 CREATE TABLE IF NOT EXISTS thingsboard.device_credentials (
187 208 id timeuuid PRIMARY KEY,
... ... @@ -203,38 +224,58 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_credentials_by_credent
203 224 WHERE credentials_id IS NOT NULL AND id IS NOT NULL
204 225 PRIMARY KEY ( credentials_id, id );
205 226
206   -
207 227 CREATE TABLE IF NOT EXISTS thingsboard.asset (
208   - id timeuuid,
209   - tenant_id timeuuid,
210   - customer_id timeuuid,
211   - name text,
212   - type text,
213   - search_text text,
214   - additional_info text,
215   - PRIMARY KEY (id, tenant_id, customer_id)
  228 + id timeuuid,
  229 + tenant_id timeuuid,
  230 + customer_id timeuuid,
  231 + name text,
  232 + type text,
  233 + search_text text,
  234 + additional_info text,
  235 + PRIMARY KEY (id, tenant_id, customer_id, type)
216 236 );
217 237
218 238 CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_tenant_and_name AS
219   - SELECT *
220   - from thingsboard.asset
221   - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL
222   - PRIMARY KEY ( tenant_id, name, id, customer_id)
223   - WITH CLUSTERING ORDER BY ( name ASC, id DESC, customer_id DESC);
  239 + SELECT *
  240 + from thingsboard.asset
  241 + 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
  242 + PRIMARY KEY ( tenant_id, name, id, customer_id, type)
  243 + WITH CLUSTERING ORDER BY ( name ASC, id DESC, customer_id DESC);
224 244
225 245 CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_tenant_and_search_text AS
226   - SELECT *
227   - from thingsboard.asset
228   - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL
229   - PRIMARY KEY ( tenant_id, search_text, id, customer_id)
230   - WITH CLUSTERING ORDER BY ( search_text ASC, id DESC, customer_id DESC);
  246 + SELECT *
  247 + from thingsboard.asset
  248 + 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
  249 + PRIMARY KEY ( tenant_id, search_text, id, customer_id, type)
  250 + WITH CLUSTERING ORDER BY ( search_text ASC, id DESC, customer_id DESC);
  251 +
  252 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_tenant_by_type_and_search_text AS
  253 + SELECT *
  254 + from thingsboard.asset
  255 + 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
  256 + PRIMARY KEY ( tenant_id, type, search_text, id, customer_id)
  257 + WITH CLUSTERING ORDER BY ( type ASC, search_text ASC, id DESC, customer_id DESC);
231 258
232 259 CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_customer_and_search_text AS
233   - SELECT *
234   - from thingsboard.asset
235   - WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL
236   - PRIMARY KEY ( customer_id, tenant_id, search_text, id )
237   - WITH CLUSTERING ORDER BY ( tenant_id DESC, search_text ASC, id DESC );
  260 + SELECT *
  261 + from thingsboard.asset
  262 + 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
  263 + PRIMARY KEY ( customer_id, tenant_id, search_text, id, type )
  264 + WITH CLUSTERING ORDER BY ( tenant_id DESC, search_text ASC, id DESC );
  265 +
  266 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_customer_by_type_and_search_text AS
  267 + SELECT *
  268 + from thingsboard.asset
  269 + 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
  270 + PRIMARY KEY ( customer_id, tenant_id, type, search_text, id )
  271 + WITH CLUSTERING ORDER BY ( tenant_id DESC, type ASC, search_text ASC, id DESC );
  272 +
  273 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_types_by_tenant AS
  274 + SELECT *
  275 + from thingsboard.asset
  276 + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND id IS NOT NULL
  277 + PRIMARY KEY ( (type, tenant_id), id, customer_id)
  278 + WITH CLUSTERING ORDER BY ( id ASC, customer_id DESC);
238 279
239 280 CREATE TABLE IF NOT EXISTS thingsboard.relation (
240 281 from_id timeuuid,
... ... @@ -247,11 +288,11 @@ CREATE TABLE IF NOT EXISTS thingsboard.relation (
247 288 );
248 289
249 290 CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.reverse_relation AS
250   -SELECT *
251   -from thingsboard.relation
252   -WHERE from_id IS NOT NULL AND from_type IS NOT NULL AND relation_type IS NOT NULL AND to_id IS NOT NULL AND to_type IS NOT NULL
253   -PRIMARY KEY ((to_id, to_type), relation_type, from_id, from_type)
254   -WITH CLUSTERING ORDER BY ( relation_type ASC, from_id ASC, from_type ASC);
  291 + SELECT *
  292 + from thingsboard.relation
  293 + WHERE from_id IS NOT NULL AND from_type IS NOT NULL AND relation_type IS NOT NULL AND to_id IS NOT NULL AND to_type IS NOT NULL
  294 + PRIMARY KEY ((to_id, to_type), relation_type, from_id, from_type)
  295 + WITH CLUSTERING ORDER BY ( relation_type ASC, from_id ASC, from_type ASC);
255 296
256 297 CREATE TABLE IF NOT EXISTS thingsboard.widgets_bundle (
257 298 id timeuuid,
... ...
... ... @@ -40,6 +40,7 @@ import org.thingsboard.server.common.data.plugin.ComponentScope;
40 40 import org.thingsboard.server.common.data.plugin.ComponentType;
41 41 import org.thingsboard.server.common.data.plugin.PluginMetaData;
42 42 import org.thingsboard.server.common.data.rule.RuleMetaData;
  43 +import org.thingsboard.server.dao.asset.AssetService;
43 44 import org.thingsboard.server.dao.component.ComponentDescriptorService;
44 45 import org.thingsboard.server.dao.customer.CustomerService;
45 46 import org.thingsboard.server.dao.dashboard.DashboardService;
... ... @@ -88,6 +89,9 @@ public abstract class AbstractServiceTest {
88 89 protected DeviceService deviceService;
89 90
90 91 @Autowired
  92 + protected AssetService assetService;
  93 +
  94 + @Autowired
91 95 protected DeviceCredentialsService deviceCredentialsService;
92 96
93 97 @Autowired
... ...
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.service;
  17 +
  18 +import com.datastax.driver.core.utils.UUIDs;
  19 +import org.apache.commons.lang3.RandomStringUtils;
  20 +import org.junit.After;
  21 +import org.junit.Assert;
  22 +import org.junit.Before;
  23 +import org.junit.Test;
  24 +import org.thingsboard.server.common.data.Customer;
  25 +import org.thingsboard.server.common.data.Tenant;
  26 +import org.thingsboard.server.common.data.asset.Asset;
  27 +import org.thingsboard.server.common.data.asset.TenantAssetType;
  28 +import org.thingsboard.server.common.data.id.CustomerId;
  29 +import org.thingsboard.server.common.data.id.TenantId;
  30 +import org.thingsboard.server.common.data.page.TextPageData;
  31 +import org.thingsboard.server.common.data.page.TextPageLink;
  32 +import org.thingsboard.server.dao.exception.DataValidationException;
  33 +
  34 +import java.util.ArrayList;
  35 +import java.util.Collections;
  36 +import java.util.List;
  37 +
  38 +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
  39 +
  40 +public class BaseAssetServiceTest extends AbstractServiceTest {
  41 +
  42 + private IdComparator<Asset> idComparator = new IdComparator<>();
  43 +
  44 + private TenantId tenantId;
  45 +
  46 + @Before
  47 + public void before() {
  48 + Tenant tenant = new Tenant();
  49 + tenant.setTitle("My tenant");
  50 + Tenant savedTenant = tenantService.saveTenant(tenant);
  51 + Assert.assertNotNull(savedTenant);
  52 + tenantId = savedTenant.getId();
  53 + }
  54 +
  55 + @After
  56 + public void after() {
  57 + tenantService.deleteTenant(tenantId);
  58 + }
  59 +
  60 + @Test
  61 + public void testSaveAsset() {
  62 + Asset asset = new Asset();
  63 + asset.setTenantId(tenantId);
  64 + asset.setName("My asset");
  65 + asset.setType("default");
  66 + Asset savedAsset = assetService.saveAsset(asset);
  67 +
  68 + Assert.assertNotNull(savedAsset);
  69 + Assert.assertNotNull(savedAsset.getId());
  70 + Assert.assertTrue(savedAsset.getCreatedTime() > 0);
  71 + Assert.assertEquals(asset.getTenantId(), savedAsset.getTenantId());
  72 + Assert.assertNotNull(savedAsset.getCustomerId());
  73 + Assert.assertEquals(NULL_UUID, savedAsset.getCustomerId().getId());
  74 + Assert.assertEquals(asset.getName(), savedAsset.getName());
  75 +
  76 + savedAsset.setName("My new asset");
  77 +
  78 + assetService.saveAsset(savedAsset);
  79 + Asset foundAsset = assetService.findAssetById(savedAsset.getId());
  80 + Assert.assertEquals(foundAsset.getName(), savedAsset.getName());
  81 +
  82 + assetService.deleteAsset(savedAsset.getId());
  83 + }
  84 +
  85 + @Test(expected = DataValidationException.class)
  86 + public void testSaveAssetWithEmptyName() {
  87 + Asset asset = new Asset();
  88 + asset.setTenantId(tenantId);
  89 + asset.setType("default");
  90 + assetService.saveAsset(asset);
  91 + }
  92 +
  93 + @Test(expected = DataValidationException.class)
  94 + public void testSaveAssetWithEmptyTenant() {
  95 + Asset asset = new Asset();
  96 + asset.setName("My asset");
  97 + asset.setType("default");
  98 + assetService.saveAsset(asset);
  99 + }
  100 +
  101 + @Test(expected = DataValidationException.class)
  102 + public void testSaveAssetWithInvalidTenant() {
  103 + Asset asset = new Asset();
  104 + asset.setName("My asset");
  105 + asset.setType("default");
  106 + asset.setTenantId(new TenantId(UUIDs.timeBased()));
  107 + assetService.saveAsset(asset);
  108 + }
  109 +
  110 + @Test(expected = DataValidationException.class)
  111 + public void testAssignAssetToNonExistentCustomer() {
  112 + Asset asset = new Asset();
  113 + asset.setName("My asset");
  114 + asset.setType("default");
  115 + asset.setTenantId(tenantId);
  116 + asset = assetService.saveAsset(asset);
  117 + try {
  118 + assetService.assignAssetToCustomer(asset.getId(), new CustomerId(UUIDs.timeBased()));
  119 + } finally {
  120 + assetService.deleteAsset(asset.getId());
  121 + }
  122 + }
  123 +
  124 + @Test(expected = DataValidationException.class)
  125 + public void testAssignAssetToCustomerFromDifferentTenant() {
  126 + Asset asset = new Asset();
  127 + asset.setName("My asset");
  128 + asset.setType("default");
  129 + asset.setTenantId(tenantId);
  130 + asset = assetService.saveAsset(asset);
  131 + Tenant tenant = new Tenant();
  132 + tenant.setTitle("Test different tenant");
  133 + tenant = tenantService.saveTenant(tenant);
  134 + Customer customer = new Customer();
  135 + customer.setTenantId(tenant.getId());
  136 + customer.setTitle("Test different customer");
  137 + customer = customerService.saveCustomer(customer);
  138 + try {
  139 + assetService.assignAssetToCustomer(asset.getId(), customer.getId());
  140 + } finally {
  141 + assetService.deleteAsset(asset.getId());
  142 + tenantService.deleteTenant(tenant.getId());
  143 + }
  144 + }
  145 +
  146 + @Test
  147 + public void testFindAssetById() {
  148 + Asset asset = new Asset();
  149 + asset.setTenantId(tenantId);
  150 + asset.setName("My asset");
  151 + asset.setType("default");
  152 + Asset savedAsset = assetService.saveAsset(asset);
  153 + Asset foundAsset = assetService.findAssetById(savedAsset.getId());
  154 + Assert.assertNotNull(foundAsset);
  155 + Assert.assertEquals(savedAsset, foundAsset);
  156 + assetService.deleteAsset(savedAsset.getId());
  157 + }
  158 +
  159 + @Test
  160 + public void testFindAssetTypesByTenantId() throws Exception {
  161 + List<Asset> assets = new ArrayList<>();
  162 + try {
  163 + for (int i=0;i<3;i++) {
  164 + Asset asset = new Asset();
  165 + asset.setTenantId(tenantId);
  166 + asset.setName("My asset B"+i);
  167 + asset.setType("typeB");
  168 + assets.add(assetService.saveAsset(asset));
  169 + }
  170 + for (int i=0;i<7;i++) {
  171 + Asset asset = new Asset();
  172 + asset.setTenantId(tenantId);
  173 + asset.setName("My asset C"+i);
  174 + asset.setType("typeC");
  175 + assets.add(assetService.saveAsset(asset));
  176 + }
  177 + for (int i=0;i<9;i++) {
  178 + Asset asset = new Asset();
  179 + asset.setTenantId(tenantId);
  180 + asset.setName("My asset A"+i);
  181 + asset.setType("typeA");
  182 + assets.add(assetService.saveAsset(asset));
  183 + }
  184 + List<TenantAssetType> assetTypes = assetService.findAssetTypesByTenantId(tenantId).get();
  185 + Assert.assertNotNull(assetTypes);
  186 + Assert.assertEquals(3, assetTypes.size());
  187 + Assert.assertEquals("typeA", assetTypes.get(0).getType());
  188 + Assert.assertEquals("typeB", assetTypes.get(1).getType());
  189 + Assert.assertEquals("typeC", assetTypes.get(2).getType());
  190 + } finally {
  191 + assets.forEach((asset) -> { assetService.deleteAsset(asset.getId()); });
  192 + }
  193 + }
  194 +
  195 + @Test
  196 + public void testDeleteAsset() {
  197 + Asset asset = new Asset();
  198 + asset.setTenantId(tenantId);
  199 + asset.setName("My asset");
  200 + asset.setType("default");
  201 + Asset savedAsset = assetService.saveAsset(asset);
  202 + Asset foundAsset = assetService.findAssetById(savedAsset.getId());
  203 + Assert.assertNotNull(foundAsset);
  204 + assetService.deleteAsset(savedAsset.getId());
  205 + foundAsset = assetService.findAssetById(savedAsset.getId());
  206 + Assert.assertNull(foundAsset);
  207 + }
  208 +
  209 + @Test
  210 + public void testFindAssetsByTenantId() {
  211 + Tenant tenant = new Tenant();
  212 + tenant.setTitle("Test tenant");
  213 + tenant = tenantService.saveTenant(tenant);
  214 +
  215 + TenantId tenantId = tenant.getId();
  216 +
  217 + List<Asset> assets = new ArrayList<>();
  218 + for (int i=0;i<178;i++) {
  219 + Asset asset = new Asset();
  220 + asset.setTenantId(tenantId);
  221 + asset.setName("Asset"+i);
  222 + asset.setType("default");
  223 + assets.add(assetService.saveAsset(asset));
  224 + }
  225 +
  226 + List<Asset> loadedAssets = new ArrayList<>();
  227 + TextPageLink pageLink = new TextPageLink(23);
  228 + TextPageData<Asset> pageData = null;
  229 + do {
  230 + pageData = assetService.findAssetsByTenantId(tenantId, pageLink);
  231 + loadedAssets.addAll(pageData.getData());
  232 + if (pageData.hasNext()) {
  233 + pageLink = pageData.getNextPageLink();
  234 + }
  235 + } while (pageData.hasNext());
  236 +
  237 + Collections.sort(assets, idComparator);
  238 + Collections.sort(loadedAssets, idComparator);
  239 +
  240 + Assert.assertEquals(assets, loadedAssets);
  241 +
  242 + assetService.deleteAssetsByTenantId(tenantId);
  243 +
  244 + pageLink = new TextPageLink(33);
  245 + pageData = assetService.findAssetsByTenantId(tenantId, pageLink);
  246 + Assert.assertFalse(pageData.hasNext());
  247 + Assert.assertTrue(pageData.getData().isEmpty());
  248 +
  249 + tenantService.deleteTenant(tenantId);
  250 + }
  251 +
  252 + @Test
  253 + public void testFindAssetsByTenantIdAndName() {
  254 + String title1 = "Asset title 1";
  255 + List<Asset> assetsTitle1 = new ArrayList<>();
  256 + for (int i=0;i<143;i++) {
  257 + Asset asset = new Asset();
  258 + asset.setTenantId(tenantId);
  259 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  260 + String name = title1+suffix;
  261 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  262 + asset.setName(name);
  263 + asset.setType("default");
  264 + assetsTitle1.add(assetService.saveAsset(asset));
  265 + }
  266 + String title2 = "Asset title 2";
  267 + List<Asset> assetsTitle2 = new ArrayList<>();
  268 + for (int i=0;i<175;i++) {
  269 + Asset asset = new Asset();
  270 + asset.setTenantId(tenantId);
  271 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  272 + String name = title2+suffix;
  273 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  274 + asset.setName(name);
  275 + asset.setType("default");
  276 + assetsTitle2.add(assetService.saveAsset(asset));
  277 + }
  278 +
  279 + List<Asset> loadedAssetsTitle1 = new ArrayList<>();
  280 + TextPageLink pageLink = new TextPageLink(15, title1);
  281 + TextPageData<Asset> pageData = null;
  282 + do {
  283 + pageData = assetService.findAssetsByTenantId(tenantId, pageLink);
  284 + loadedAssetsTitle1.addAll(pageData.getData());
  285 + if (pageData.hasNext()) {
  286 + pageLink = pageData.getNextPageLink();
  287 + }
  288 + } while (pageData.hasNext());
  289 +
  290 + Collections.sort(assetsTitle1, idComparator);
  291 + Collections.sort(loadedAssetsTitle1, idComparator);
  292 +
  293 + Assert.assertEquals(assetsTitle1, loadedAssetsTitle1);
  294 +
  295 + List<Asset> loadedAssetsTitle2 = new ArrayList<>();
  296 + pageLink = new TextPageLink(4, title2);
  297 + do {
  298 + pageData = assetService.findAssetsByTenantId(tenantId, pageLink);
  299 + loadedAssetsTitle2.addAll(pageData.getData());
  300 + if (pageData.hasNext()) {
  301 + pageLink = pageData.getNextPageLink();
  302 + }
  303 + } while (pageData.hasNext());
  304 +
  305 + Collections.sort(assetsTitle2, idComparator);
  306 + Collections.sort(loadedAssetsTitle2, idComparator);
  307 +
  308 + Assert.assertEquals(assetsTitle2, loadedAssetsTitle2);
  309 +
  310 + for (Asset asset : loadedAssetsTitle1) {
  311 + assetService.deleteAsset(asset.getId());
  312 + }
  313 +
  314 + pageLink = new TextPageLink(4, title1);
  315 + pageData = assetService.findAssetsByTenantId(tenantId, pageLink);
  316 + Assert.assertFalse(pageData.hasNext());
  317 + Assert.assertEquals(0, pageData.getData().size());
  318 +
  319 + for (Asset asset : loadedAssetsTitle2) {
  320 + assetService.deleteAsset(asset.getId());
  321 + }
  322 +
  323 + pageLink = new TextPageLink(4, title2);
  324 + pageData = assetService.findAssetsByTenantId(tenantId, pageLink);
  325 + Assert.assertFalse(pageData.hasNext());
  326 + Assert.assertEquals(0, pageData.getData().size());
  327 + }
  328 +
  329 + @Test
  330 + public void testFindAssetsByTenantIdAndType() {
  331 + String title1 = "Asset title 1";
  332 + String type1 = "typeA";
  333 + List<Asset> assetsType1 = new ArrayList<>();
  334 + for (int i=0;i<143;i++) {
  335 + Asset asset = new Asset();
  336 + asset.setTenantId(tenantId);
  337 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  338 + String name = title1+suffix;
  339 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  340 + asset.setName(name);
  341 + asset.setType(type1);
  342 + assetsType1.add(assetService.saveAsset(asset));
  343 + }
  344 + String title2 = "Asset title 2";
  345 + String type2 = "typeB";
  346 + List<Asset> assetsType2 = new ArrayList<>();
  347 + for (int i=0;i<175;i++) {
  348 + Asset asset = new Asset();
  349 + asset.setTenantId(tenantId);
  350 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  351 + String name = title2+suffix;
  352 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  353 + asset.setName(name);
  354 + asset.setType(type2);
  355 + assetsType2.add(assetService.saveAsset(asset));
  356 + }
  357 +
  358 + List<Asset> loadedAssetsType1 = new ArrayList<>();
  359 + TextPageLink pageLink = new TextPageLink(15);
  360 + TextPageData<Asset> pageData = null;
  361 + do {
  362 + pageData = assetService.findAssetsByTenantIdAndType(tenantId, type1, pageLink);
  363 + loadedAssetsType1.addAll(pageData.getData());
  364 + if (pageData.hasNext()) {
  365 + pageLink = pageData.getNextPageLink();
  366 + }
  367 + } while (pageData.hasNext());
  368 +
  369 + Collections.sort(assetsType1, idComparator);
  370 + Collections.sort(loadedAssetsType1, idComparator);
  371 +
  372 + Assert.assertEquals(assetsType1, loadedAssetsType1);
  373 +
  374 + List<Asset> loadedAssetsType2 = new ArrayList<>();
  375 + pageLink = new TextPageLink(4);
  376 + do {
  377 + pageData = assetService.findAssetsByTenantIdAndType(tenantId, type2, pageLink);
  378 + loadedAssetsType2.addAll(pageData.getData());
  379 + if (pageData.hasNext()) {
  380 + pageLink = pageData.getNextPageLink();
  381 + }
  382 + } while (pageData.hasNext());
  383 +
  384 + Collections.sort(assetsType2, idComparator);
  385 + Collections.sort(loadedAssetsType2, idComparator);
  386 +
  387 + Assert.assertEquals(assetsType2, loadedAssetsType2);
  388 +
  389 + for (Asset asset : loadedAssetsType1) {
  390 + assetService.deleteAsset(asset.getId());
  391 + }
  392 +
  393 + pageLink = new TextPageLink(4);
  394 + pageData = assetService.findAssetsByTenantIdAndType(tenantId, type1, pageLink);
  395 + Assert.assertFalse(pageData.hasNext());
  396 + Assert.assertEquals(0, pageData.getData().size());
  397 +
  398 + for (Asset asset : loadedAssetsType2) {
  399 + assetService.deleteAsset(asset.getId());
  400 + }
  401 +
  402 + pageLink = new TextPageLink(4);
  403 + pageData = assetService.findAssetsByTenantIdAndType(tenantId, type2, pageLink);
  404 + Assert.assertFalse(pageData.hasNext());
  405 + Assert.assertEquals(0, pageData.getData().size());
  406 + }
  407 +
  408 + @Test
  409 + public void testFindAssetsByTenantIdAndCustomerId() {
  410 + Tenant tenant = new Tenant();
  411 + tenant.setTitle("Test tenant");
  412 + tenant = tenantService.saveTenant(tenant);
  413 +
  414 + TenantId tenantId = tenant.getId();
  415 +
  416 + Customer customer = new Customer();
  417 + customer.setTitle("Test customer");
  418 + customer.setTenantId(tenantId);
  419 + customer = customerService.saveCustomer(customer);
  420 + CustomerId customerId = customer.getId();
  421 +
  422 + List<Asset> assets = new ArrayList<>();
  423 + for (int i=0;i<278;i++) {
  424 + Asset asset = new Asset();
  425 + asset.setTenantId(tenantId);
  426 + asset.setName("Asset"+i);
  427 + asset.setType("default");
  428 + asset = assetService.saveAsset(asset);
  429 + assets.add(assetService.assignAssetToCustomer(asset.getId(), customerId));
  430 + }
  431 +
  432 + List<Asset> loadedAssets = new ArrayList<>();
  433 + TextPageLink pageLink = new TextPageLink(23);
  434 + TextPageData<Asset> pageData = null;
  435 + do {
  436 + pageData = assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink);
  437 + loadedAssets.addAll(pageData.getData());
  438 + if (pageData.hasNext()) {
  439 + pageLink = pageData.getNextPageLink();
  440 + }
  441 + } while (pageData.hasNext());
  442 +
  443 + Collections.sort(assets, idComparator);
  444 + Collections.sort(loadedAssets, idComparator);
  445 +
  446 + Assert.assertEquals(assets, loadedAssets);
  447 +
  448 + assetService.unassignCustomerAssets(tenantId, customerId);
  449 +
  450 + pageLink = new TextPageLink(33);
  451 + pageData = assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink);
  452 + Assert.assertFalse(pageData.hasNext());
  453 + Assert.assertTrue(pageData.getData().isEmpty());
  454 +
  455 + tenantService.deleteTenant(tenantId);
  456 + }
  457 +
  458 + @Test
  459 + public void testFindAssetsByTenantIdCustomerIdAndName() {
  460 +
  461 + Customer customer = new Customer();
  462 + customer.setTitle("Test customer");
  463 + customer.setTenantId(tenantId);
  464 + customer = customerService.saveCustomer(customer);
  465 + CustomerId customerId = customer.getId();
  466 +
  467 + String title1 = "Asset title 1";
  468 + List<Asset> assetsTitle1 = new ArrayList<>();
  469 + for (int i=0;i<175;i++) {
  470 + Asset asset = new Asset();
  471 + asset.setTenantId(tenantId);
  472 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  473 + String name = title1+suffix;
  474 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  475 + asset.setName(name);
  476 + asset.setType("default");
  477 + asset = assetService.saveAsset(asset);
  478 + assetsTitle1.add(assetService.assignAssetToCustomer(asset.getId(), customerId));
  479 + }
  480 + String title2 = "Asset title 2";
  481 + List<Asset> assetsTitle2 = new ArrayList<>();
  482 + for (int i=0;i<143;i++) {
  483 + Asset asset = new Asset();
  484 + asset.setTenantId(tenantId);
  485 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  486 + String name = title2+suffix;
  487 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  488 + asset.setName(name);
  489 + asset.setType("default");
  490 + asset = assetService.saveAsset(asset);
  491 + assetsTitle2.add(assetService.assignAssetToCustomer(asset.getId(), customerId));
  492 + }
  493 +
  494 + List<Asset> loadedAssetsTitle1 = new ArrayList<>();
  495 + TextPageLink pageLink = new TextPageLink(15, title1);
  496 + TextPageData<Asset> pageData = null;
  497 + do {
  498 + pageData = assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink);
  499 + loadedAssetsTitle1.addAll(pageData.getData());
  500 + if (pageData.hasNext()) {
  501 + pageLink = pageData.getNextPageLink();
  502 + }
  503 + } while (pageData.hasNext());
  504 +
  505 + Collections.sort(assetsTitle1, idComparator);
  506 + Collections.sort(loadedAssetsTitle1, idComparator);
  507 +
  508 + Assert.assertEquals(assetsTitle1, loadedAssetsTitle1);
  509 +
  510 + List<Asset> loadedAssetsTitle2 = new ArrayList<>();
  511 + pageLink = new TextPageLink(4, title2);
  512 + do {
  513 + pageData = assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink);
  514 + loadedAssetsTitle2.addAll(pageData.getData());
  515 + if (pageData.hasNext()) {
  516 + pageLink = pageData.getNextPageLink();
  517 + }
  518 + } while (pageData.hasNext());
  519 +
  520 + Collections.sort(assetsTitle2, idComparator);
  521 + Collections.sort(loadedAssetsTitle2, idComparator);
  522 +
  523 + Assert.assertEquals(assetsTitle2, loadedAssetsTitle2);
  524 +
  525 + for (Asset asset : loadedAssetsTitle1) {
  526 + assetService.deleteAsset(asset.getId());
  527 + }
  528 +
  529 + pageLink = new TextPageLink(4, title1);
  530 + pageData = assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink);
  531 + Assert.assertFalse(pageData.hasNext());
  532 + Assert.assertEquals(0, pageData.getData().size());
  533 +
  534 + for (Asset asset : loadedAssetsTitle2) {
  535 + assetService.deleteAsset(asset.getId());
  536 + }
  537 +
  538 + pageLink = new TextPageLink(4, title2);
  539 + pageData = assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink);
  540 + Assert.assertFalse(pageData.hasNext());
  541 + Assert.assertEquals(0, pageData.getData().size());
  542 + customerService.deleteCustomer(customerId);
  543 + }
  544 +
  545 + @Test
  546 + public void testFindAssetsByTenantIdCustomerIdAndType() {
  547 +
  548 + Customer customer = new Customer();
  549 + customer.setTitle("Test customer");
  550 + customer.setTenantId(tenantId);
  551 + customer = customerService.saveCustomer(customer);
  552 + CustomerId customerId = customer.getId();
  553 +
  554 + String title1 = "Asset title 1";
  555 + String type1 = "typeC";
  556 + List<Asset> assetsType1 = new ArrayList<>();
  557 + for (int i=0;i<175;i++) {
  558 + Asset asset = new Asset();
  559 + asset.setTenantId(tenantId);
  560 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  561 + String name = title1+suffix;
  562 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  563 + asset.setName(name);
  564 + asset.setType(type1);
  565 + asset = assetService.saveAsset(asset);
  566 + assetsType1.add(assetService.assignAssetToCustomer(asset.getId(), customerId));
  567 + }
  568 + String title2 = "Asset title 2";
  569 + String type2 = "typeD";
  570 + List<Asset> assetsType2 = new ArrayList<>();
  571 + for (int i=0;i<143;i++) {
  572 + Asset asset = new Asset();
  573 + asset.setTenantId(tenantId);
  574 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  575 + String name = title2+suffix;
  576 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  577 + asset.setName(name);
  578 + asset.setType(type2);
  579 + asset = assetService.saveAsset(asset);
  580 + assetsType2.add(assetService.assignAssetToCustomer(asset.getId(), customerId));
  581 + }
  582 +
  583 + List<Asset> loadedAssetsType1 = new ArrayList<>();
  584 + TextPageLink pageLink = new TextPageLink(15);
  585 + TextPageData<Asset> pageData = null;
  586 + do {
  587 + pageData = assetService.findAssetsByTenantIdAndCustomerIdAndType(tenantId, customerId, type1, pageLink);
  588 + loadedAssetsType1.addAll(pageData.getData());
  589 + if (pageData.hasNext()) {
  590 + pageLink = pageData.getNextPageLink();
  591 + }
  592 + } while (pageData.hasNext());
  593 +
  594 + Collections.sort(assetsType1, idComparator);
  595 + Collections.sort(loadedAssetsType1, idComparator);
  596 +
  597 + Assert.assertEquals(assetsType1, loadedAssetsType1);
  598 +
  599 + List<Asset> loadedAssetsType2 = new ArrayList<>();
  600 + pageLink = new TextPageLink(4);
  601 + do {
  602 + pageData = assetService.findAssetsByTenantIdAndCustomerIdAndType(tenantId, customerId, type2, pageLink);
  603 + loadedAssetsType2.addAll(pageData.getData());
  604 + if (pageData.hasNext()) {
  605 + pageLink = pageData.getNextPageLink();
  606 + }
  607 + } while (pageData.hasNext());
  608 +
  609 + Collections.sort(assetsType2, idComparator);
  610 + Collections.sort(loadedAssetsType2, idComparator);
  611 +
  612 + Assert.assertEquals(assetsType2, loadedAssetsType2);
  613 +
  614 + for (Asset asset : loadedAssetsType1) {
  615 + assetService.deleteAsset(asset.getId());
  616 + }
  617 +
  618 + pageLink = new TextPageLink(4);
  619 + pageData = assetService.findAssetsByTenantIdAndCustomerIdAndType(tenantId, customerId, type1, pageLink);
  620 + Assert.assertFalse(pageData.hasNext());
  621 + Assert.assertEquals(0, pageData.getData().size());
  622 +
  623 + for (Asset asset : loadedAssetsType2) {
  624 + assetService.deleteAsset(asset.getId());
  625 + }
  626 +
  627 + pageLink = new TextPageLink(4);
  628 + pageData = assetService.findAssetsByTenantIdAndCustomerIdAndType(tenantId, customerId, type2, pageLink);
  629 + Assert.assertFalse(pageData.hasNext());
  630 + Assert.assertEquals(0, pageData.getData().size());
  631 + customerService.deleteCustomer(customerId);
  632 + }
  633 +
  634 +}
... ...
... ... @@ -58,6 +58,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest {
58 58 public void testSaveDeviceCredentialsWithEmptyDevice() {
59 59 Device device = new Device();
60 60 device.setName("My device");
  61 + device.setType("default");
61 62 device.setTenantId(tenantId);
62 63 device = deviceService.saveDevice(device);
63 64 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getId());
... ... @@ -73,6 +74,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest {
73 74 public void testSaveDeviceCredentialsWithEmptyCredentialsType() {
74 75 Device device = new Device();
75 76 device.setName("My device");
  77 + device.setType("default");
76 78 device.setTenantId(tenantId);
77 79 device = deviceService.saveDevice(device);
78 80 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getId());
... ... @@ -88,6 +90,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest {
88 90 public void testSaveDeviceCredentialsWithEmptyCredentialsId() {
89 91 Device device = new Device();
90 92 device.setName("My device");
  93 + device.setType("default");
91 94 device.setTenantId(tenantId);
92 95 device = deviceService.saveDevice(device);
93 96 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getId());
... ... @@ -103,6 +106,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest {
103 106 public void testSaveNonExistentDeviceCredentials() {
104 107 Device device = new Device();
105 108 device.setName("My device");
  109 + device.setType("default");
106 110 device.setTenantId(tenantId);
107 111 device = deviceService.saveDevice(device);
108 112 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getId());
... ... @@ -122,6 +126,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest {
122 126 public void testSaveDeviceCredentialsWithNonExistentDevice() {
123 127 Device device = new Device();
124 128 device.setName("My device");
  129 + device.setType("default");
125 130 device.setTenantId(tenantId);
126 131 device = deviceService.saveDevice(device);
127 132 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getId());
... ... @@ -137,6 +142,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest {
137 142 public void testSaveDeviceCredentialsWithInvalidCredemtialsIdLength() {
138 143 Device device = new Device();
139 144 device.setName("My device");
  145 + device.setType("default");
140 146 device.setTenantId(tenantId);
141 147 device = deviceService.saveDevice(device);
142 148 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getId());
... ... @@ -153,6 +159,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest {
153 159 Device device = new Device();
154 160 device.setTenantId(tenantId);
155 161 device.setName("My device");
  162 + device.setType("default");
156 163 Device savedDevice = deviceService.saveDevice(device);
157 164 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedDevice.getId());
158 165 Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId());
... ... @@ -166,6 +173,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest {
166 173 Device device = new Device();
167 174 device.setTenantId(tenantId);
168 175 device.setName("My device");
  176 + device.setType("default");
169 177 Device savedDevice = deviceService.saveDevice(device);
170 178 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedDevice.getId());
171 179 Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId());
... ... @@ -181,6 +189,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest {
181 189 Device device = new Device();
182 190 device.setTenantId(tenantId);
183 191 device.setName("My device");
  192 + device.setType("default");
184 193 Device savedDevice = deviceService.saveDevice(device);
185 194 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedDevice.getId());
186 195 Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId());
... ...
... ... @@ -24,6 +24,7 @@ import org.junit.Test;
24 24 import org.thingsboard.server.common.data.Customer;
25 25 import org.thingsboard.server.common.data.Device;
26 26 import org.thingsboard.server.common.data.Tenant;
  27 +import org.thingsboard.server.common.data.TenantDeviceType;
27 28 import org.thingsboard.server.common.data.id.CustomerId;
28 29 import org.thingsboard.server.common.data.id.DeviceCredentialsId;
29 30 import org.thingsboard.server.common.data.id.DeviceId;
... ... @@ -37,6 +38,7 @@ import org.thingsboard.server.dao.exception.DataValidationException;
37 38 import java.util.ArrayList;
38 39 import java.util.Collections;
39 40 import java.util.List;
  41 +import java.util.concurrent.Executors;
40 42
41 43 import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
42 44
... ... @@ -65,6 +67,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
65 67 Device device = new Device();
66 68 device.setTenantId(tenantId);
67 69 device.setName("My device");
  70 + device.setType("default");
68 71 Device savedDevice = deviceService.saveDevice(device);
69 72
70 73 Assert.assertNotNull(savedDevice);
... ... @@ -95,6 +98,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
95 98 @Test(expected = DataValidationException.class)
96 99 public void testSaveDeviceWithEmptyName() {
97 100 Device device = new Device();
  101 + device.setType("default");
98 102 device.setTenantId(tenantId);
99 103 deviceService.saveDevice(device);
100 104 }
... ... @@ -103,6 +107,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
103 107 public void testSaveDeviceWithEmptyTenant() {
104 108 Device device = new Device();
105 109 device.setName("My device");
  110 + device.setType("default");
106 111 deviceService.saveDevice(device);
107 112 }
108 113
... ... @@ -110,6 +115,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
110 115 public void testSaveDeviceWithInvalidTenant() {
111 116 Device device = new Device();
112 117 device.setName("My device");
  118 + device.setType("default");
113 119 device.setTenantId(new TenantId(UUIDs.timeBased()));
114 120 deviceService.saveDevice(device);
115 121 }
... ... @@ -118,6 +124,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
118 124 public void testAssignDeviceToNonExistentCustomer() {
119 125 Device device = new Device();
120 126 device.setName("My device");
  127 + device.setType("default");
121 128 device.setTenantId(tenantId);
122 129 device = deviceService.saveDevice(device);
123 130 try {
... ... @@ -131,6 +138,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
131 138 public void testAssignDeviceToCustomerFromDifferentTenant() {
132 139 Device device = new Device();
133 140 device.setName("My device");
  141 + device.setType("default");
134 142 device.setTenantId(tenantId);
135 143 device = deviceService.saveDevice(device);
136 144 Tenant tenant = new Tenant();
... ... @@ -153,18 +161,56 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
153 161 Device device = new Device();
154 162 device.setTenantId(tenantId);
155 163 device.setName("My device");
  164 + device.setType("default");
156 165 Device savedDevice = deviceService.saveDevice(device);
157 166 Device foundDevice = deviceService.findDeviceById(savedDevice.getId());
158 167 Assert.assertNotNull(foundDevice);
159 168 Assert.assertEquals(savedDevice, foundDevice);
160 169 deviceService.deleteDevice(savedDevice.getId());
161 170 }
  171 +
  172 + @Test
  173 + public void testFindDeviceTypesByTenantId() throws Exception {
  174 + List<Device> devices = new ArrayList<>();
  175 + try {
  176 + for (int i=0;i<3;i++) {
  177 + Device device = new Device();
  178 + device.setTenantId(tenantId);
  179 + device.setName("My device B"+i);
  180 + device.setType("typeB");
  181 + devices.add(deviceService.saveDevice(device));
  182 + }
  183 + for (int i=0;i<7;i++) {
  184 + Device device = new Device();
  185 + device.setTenantId(tenantId);
  186 + device.setName("My device C"+i);
  187 + device.setType("typeC");
  188 + devices.add(deviceService.saveDevice(device));
  189 + }
  190 + for (int i=0;i<9;i++) {
  191 + Device device = new Device();
  192 + device.setTenantId(tenantId);
  193 + device.setName("My device A"+i);
  194 + device.setType("typeA");
  195 + devices.add(deviceService.saveDevice(device));
  196 + }
  197 + List<TenantDeviceType> deviceTypes = deviceService.findDeviceTypesByTenantId(tenantId).get();
  198 + Assert.assertNotNull(deviceTypes);
  199 + Assert.assertEquals(3, deviceTypes.size());
  200 + Assert.assertEquals("typeA", deviceTypes.get(0).getType());
  201 + Assert.assertEquals("typeB", deviceTypes.get(1).getType());
  202 + Assert.assertEquals("typeC", deviceTypes.get(2).getType());
  203 + } finally {
  204 + devices.forEach((device) -> { deviceService.deleteDevice(device.getId()); });
  205 + }
  206 + }
162 207
163 208 @Test
164 209 public void testDeleteDevice() {
165 210 Device device = new Device();
166 211 device.setTenantId(tenantId);
167 212 device.setName("My device");
  213 + device.setType("default");
168 214 Device savedDevice = deviceService.saveDevice(device);
169 215 Device foundDevice = deviceService.findDeviceById(savedDevice.getId());
170 216 Assert.assertNotNull(foundDevice);
... ... @@ -188,6 +234,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
188 234 Device device = new Device();
189 235 device.setTenantId(tenantId);
190 236 device.setName("Device"+i);
  237 + device.setType("default");
191 238 devices.add(deviceService.saveDevice(device));
192 239 }
193 240
... ... @@ -216,7 +263,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
216 263
217 264 tenantService.deleteTenant(tenantId);
218 265 }
219   -
  266 +
220 267 @Test
221 268 public void testFindDevicesByTenantIdAndName() {
222 269 String title1 = "Device title 1";
... ... @@ -228,6 +275,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
228 275 String name = title1+suffix;
229 276 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
230 277 device.setName(name);
  278 + device.setType("default");
231 279 devicesTitle1.add(deviceService.saveDevice(device));
232 280 }
233 281 String title2 = "Device title 2";
... ... @@ -239,6 +287,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
239 287 String name = title2+suffix;
240 288 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
241 289 device.setName(name);
  290 + device.setType("default");
242 291 devicesTitle2.add(deviceService.saveDevice(device));
243 292 }
244 293
... ... @@ -291,6 +340,85 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
291 340 Assert.assertFalse(pageData.hasNext());
292 341 Assert.assertEquals(0, pageData.getData().size());
293 342 }
  343 +
  344 + @Test
  345 + public void testFindDevicesByTenantIdAndType() {
  346 + String title1 = "Device title 1";
  347 + String type1 = "typeA";
  348 + List<Device> devicesType1 = new ArrayList<>();
  349 + for (int i=0;i<143;i++) {
  350 + Device device = new Device();
  351 + device.setTenantId(tenantId);
  352 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  353 + String name = title1+suffix;
  354 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  355 + device.setName(name);
  356 + device.setType(type1);
  357 + devicesType1.add(deviceService.saveDevice(device));
  358 + }
  359 + String title2 = "Device title 2";
  360 + String type2 = "typeB";
  361 + List<Device> devicesType2 = new ArrayList<>();
  362 + for (int i=0;i<175;i++) {
  363 + Device device = new Device();
  364 + device.setTenantId(tenantId);
  365 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  366 + String name = title2+suffix;
  367 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  368 + device.setName(name);
  369 + device.setType(type2);
  370 + devicesType2.add(deviceService.saveDevice(device));
  371 + }
  372 +
  373 + List<Device> loadedDevicesType1 = new ArrayList<>();
  374 + TextPageLink pageLink = new TextPageLink(15);
  375 + TextPageData<Device> pageData = null;
  376 + do {
  377 + pageData = deviceService.findDevicesByTenantIdAndType(tenantId, type1, pageLink);
  378 + loadedDevicesType1.addAll(pageData.getData());
  379 + if (pageData.hasNext()) {
  380 + pageLink = pageData.getNextPageLink();
  381 + }
  382 + } while (pageData.hasNext());
  383 +
  384 + Collections.sort(devicesType1, idComparator);
  385 + Collections.sort(loadedDevicesType1, idComparator);
  386 +
  387 + Assert.assertEquals(devicesType1, loadedDevicesType1);
  388 +
  389 + List<Device> loadedDevicesType2 = new ArrayList<>();
  390 + pageLink = new TextPageLink(4);
  391 + do {
  392 + pageData = deviceService.findDevicesByTenantIdAndType(tenantId, type2, pageLink);
  393 + loadedDevicesType2.addAll(pageData.getData());
  394 + if (pageData.hasNext()) {
  395 + pageLink = pageData.getNextPageLink();
  396 + }
  397 + } while (pageData.hasNext());
  398 +
  399 + Collections.sort(devicesType2, idComparator);
  400 + Collections.sort(loadedDevicesType2, idComparator);
  401 +
  402 + Assert.assertEquals(devicesType2, loadedDevicesType2);
  403 +
  404 + for (Device device : loadedDevicesType1) {
  405 + deviceService.deleteDevice(device.getId());
  406 + }
  407 +
  408 + pageLink = new TextPageLink(4);
  409 + pageData = deviceService.findDevicesByTenantIdAndType(tenantId, type1, pageLink);
  410 + Assert.assertFalse(pageData.hasNext());
  411 + Assert.assertEquals(0, pageData.getData().size());
  412 +
  413 + for (Device device : loadedDevicesType2) {
  414 + deviceService.deleteDevice(device.getId());
  415 + }
  416 +
  417 + pageLink = new TextPageLink(4);
  418 + pageData = deviceService.findDevicesByTenantIdAndType(tenantId, type2, pageLink);
  419 + Assert.assertFalse(pageData.hasNext());
  420 + Assert.assertEquals(0, pageData.getData().size());
  421 + }
294 422
295 423 @Test
296 424 public void testFindDevicesByTenantIdAndCustomerId() {
... ... @@ -311,6 +439,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
311 439 Device device = new Device();
312 440 device.setTenantId(tenantId);
313 441 device.setName("Device"+i);
  442 + device.setType("default");
314 443 device = deviceService.saveDevice(device);
315 444 devices.add(deviceService.assignDeviceToCustomer(device.getId(), customerId));
316 445 }
... ... @@ -359,6 +488,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
359 488 String name = title1+suffix;
360 489 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
361 490 device.setName(name);
  491 + device.setType("default");
362 492 device = deviceService.saveDevice(device);
363 493 devicesTitle1.add(deviceService.assignDeviceToCustomer(device.getId(), customerId));
364 494 }
... ... @@ -371,6 +501,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
371 501 String name = title2+suffix;
372 502 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
373 503 device.setName(name);
  504 + device.setType("default");
374 505 device = deviceService.saveDevice(device);
375 506 devicesTitle2.add(deviceService.assignDeviceToCustomer(device.getId(), customerId));
376 507 }
... ... @@ -425,4 +556,94 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
425 556 Assert.assertEquals(0, pageData.getData().size());
426 557 customerService.deleteCustomer(customerId);
427 558 }
  559 +
  560 + @Test
  561 + public void testFindDevicesByTenantIdCustomerIdAndType() {
  562 +
  563 + Customer customer = new Customer();
  564 + customer.setTitle("Test customer");
  565 + customer.setTenantId(tenantId);
  566 + customer = customerService.saveCustomer(customer);
  567 + CustomerId customerId = customer.getId();
  568 +
  569 + String title1 = "Device title 1";
  570 + String type1 = "typeC";
  571 + List<Device> devicesType1 = new ArrayList<>();
  572 + for (int i=0;i<175;i++) {
  573 + Device device = new Device();
  574 + device.setTenantId(tenantId);
  575 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  576 + String name = title1+suffix;
  577 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  578 + device.setName(name);
  579 + device.setType(type1);
  580 + device = deviceService.saveDevice(device);
  581 + devicesType1.add(deviceService.assignDeviceToCustomer(device.getId(), customerId));
  582 + }
  583 + String title2 = "Device title 2";
  584 + String type2 = "typeD";
  585 + List<Device> devicesType2 = new ArrayList<>();
  586 + for (int i=0;i<143;i++) {
  587 + Device device = new Device();
  588 + device.setTenantId(tenantId);
  589 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  590 + String name = title2+suffix;
  591 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  592 + device.setName(name);
  593 + device.setType(type2);
  594 + device = deviceService.saveDevice(device);
  595 + devicesType2.add(deviceService.assignDeviceToCustomer(device.getId(), customerId));
  596 + }
  597 +
  598 + List<Device> loadedDevicesType1 = new ArrayList<>();
  599 + TextPageLink pageLink = new TextPageLink(15);
  600 + TextPageData<Device> pageData = null;
  601 + do {
  602 + pageData = deviceService.findDevicesByTenantIdAndCustomerIdAndType(tenantId, customerId, type1, pageLink);
  603 + loadedDevicesType1.addAll(pageData.getData());
  604 + if (pageData.hasNext()) {
  605 + pageLink = pageData.getNextPageLink();
  606 + }
  607 + } while (pageData.hasNext());
  608 +
  609 + Collections.sort(devicesType1, idComparator);
  610 + Collections.sort(loadedDevicesType1, idComparator);
  611 +
  612 + Assert.assertEquals(devicesType1, loadedDevicesType1);
  613 +
  614 + List<Device> loadedDevicesType2 = new ArrayList<>();
  615 + pageLink = new TextPageLink(4);
  616 + do {
  617 + pageData = deviceService.findDevicesByTenantIdAndCustomerIdAndType(tenantId, customerId, type2, pageLink);
  618 + loadedDevicesType2.addAll(pageData.getData());
  619 + if (pageData.hasNext()) {
  620 + pageLink = pageData.getNextPageLink();
  621 + }
  622 + } while (pageData.hasNext());
  623 +
  624 + Collections.sort(devicesType2, idComparator);
  625 + Collections.sort(loadedDevicesType2, idComparator);
  626 +
  627 + Assert.assertEquals(devicesType2, loadedDevicesType2);
  628 +
  629 + for (Device device : loadedDevicesType1) {
  630 + deviceService.deleteDevice(device.getId());
  631 + }
  632 +
  633 + pageLink = new TextPageLink(4);
  634 + pageData = deviceService.findDevicesByTenantIdAndCustomerIdAndType(tenantId, customerId, type1, pageLink);
  635 + Assert.assertFalse(pageData.hasNext());
  636 + Assert.assertEquals(0, pageData.getData().size());
  637 +
  638 + for (Device device : loadedDevicesType2) {
  639 + deviceService.deleteDevice(device.getId());
  640 + }
  641 +
  642 + pageLink = new TextPageLink(4);
  643 + pageData = deviceService.findDevicesByTenantIdAndCustomerIdAndType(tenantId, customerId, type2, pageLink);
  644 + Assert.assertFalse(pageData.hasNext());
  645 + Assert.assertEquals(0, pageData.getData().size());
  646 + customerService.deleteCustomer(customerId);
  647 + }
  648 +
428 649 }
... ...
1 1 CASSANDRA_DATA_DIR=/home/docker/cassandra_volume
  2 +
  3 +# cassandra schema container environment variables
  4 +CREATE_SCHEMA=true
  5 +ADD_SYSTEM_DATA=false
  6 +ADD_DEMO_DATA=false
  7 +CASSANDRA_URL=cassandra
\ No newline at end of file
... ...
  1 +#
  2 +# Copyright © 2016-2017 The Thingsboard Authors
  3 +#
  4 +# Licensed under the Apache License, Version 2.0 (the "License");
  5 +# you may not use this file except in compliance with the License.
  6 +# You may obtain a copy of the License at
  7 +#
  8 +# http://www.apache.org/licenses/LICENSE-2.0
  9 +#
  10 +# Unless required by applicable law or agreed to in writing, software
  11 +# distributed under the License is distributed on an "AS IS" BASIS,
  12 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +# See the License for the specific language governing permissions and
  14 +# limitations under the License.
  15 +#
  16 +
  17 +apiVersion: v1
  18 +kind: Service
  19 +metadata:
  20 + name: cassandra-headless
  21 + labels:
  22 + app: cassandra-headless
  23 +spec:
  24 + ports:
  25 + - port: 9042
  26 + name: cql
  27 + clusterIP: None
  28 + selector:
  29 + app: cassandra
  30 +---
  31 +apiVersion: "apps/v1beta1"
  32 +kind: StatefulSet
  33 +metadata:
  34 + name: cassandra
  35 +spec:
  36 + serviceName: cassandra-headless
  37 + replicas: 2
  38 + template:
  39 + metadata:
  40 + labels:
  41 + app: cassandra
  42 + spec:
  43 + nodeSelector:
  44 + machinetype: other
  45 + affinity:
  46 + podAntiAffinity:
  47 + requiredDuringSchedulingIgnoredDuringExecution:
  48 + - labelSelector:
  49 + matchExpressions:
  50 + - key: "app"
  51 + operator: In
  52 + values:
  53 + - cassandra-headless
  54 + topologyKey: "kubernetes.io/hostname"
  55 + containers:
  56 + - name: cassandra
  57 + image: cassandra:3.9
  58 + imagePullPolicy: Always
  59 + ports:
  60 + - containerPort: 7000
  61 + name: intra-node
  62 + - containerPort: 7001
  63 + name: tls-intra-node
  64 + - containerPort: 7199
  65 + name: jmx
  66 + - containerPort: 9042
  67 + name: cql
  68 + - containerPort: 9160
  69 + name: thrift
  70 + securityContext:
  71 + capabilities:
  72 + add:
  73 + - IPC_LOCK
  74 + lifecycle:
  75 + preStop:
  76 + exec:
  77 + command: ["/bin/sh", "-c", "PID=$(pidof java) && kill $PID && while ps -p $PID > /dev/null; do sleep 1; done"]
  78 + env:
  79 + - name: MAX_HEAP_SIZE
  80 + value: 2048M
  81 + - name: HEAP_NEWSIZE
  82 + value: 100M
  83 + - name: CASSANDRA_SEEDS
  84 + value: "cassandra-0.cassandra-headless.default.svc.cluster.local"
  85 + - name: CASSANDRA_CLUSTER_NAME
  86 + value: "Thingsboard-Cluster"
  87 + - name: CASSANDRA_DC
  88 + value: "DC1-Thingsboard-Cluster"
  89 + - name: CASSANDRA_RACK
  90 + value: "Rack-Thingsboard-Cluster"
  91 + - name: CASSANDRA_AUTO_BOOTSTRAP
  92 + value: "false"
  93 + - name: POD_IP
  94 + valueFrom:
  95 + fieldRef:
  96 + fieldPath: status.podIP
  97 + - name: POD_NAMESPACE
  98 + valueFrom:
  99 + fieldRef:
  100 + fieldPath: metadata.namespace
  101 + readinessProbe:
  102 + exec:
  103 + command:
  104 + - /bin/bash
  105 + - -c
  106 + - /ready-probe.sh
  107 + initialDelaySeconds: 15
  108 + timeoutSeconds: 5
  109 + volumeMounts:
  110 + - name: cassandra-data
  111 + mountPath: /var/lib/cassandra/data
  112 + - name: cassandra-commitlog
  113 + mountPath: /var/lib/cassandra/commitlog
  114 + volumeClaimTemplates:
  115 + - metadata:
  116 + name: cassandra-data
  117 + annotations:
  118 + volume.beta.kubernetes.io/storage-class: fast
  119 + spec:
  120 + accessModes: [ "ReadWriteOnce" ]
  121 + resources:
  122 + requests:
  123 + storage: 3Gi
  124 + - metadata:
  125 + name: cassandra-commitlog
  126 + annotations:
  127 + volume.beta.kubernetes.io/storage-class: fast
  128 + spec:
  129 + accessModes: [ "ReadWriteOnce" ]
  130 + resources:
  131 + requests:
  132 + storage: 2Gi
\ No newline at end of file
... ...
docker/common/common.yaml renamed from docker/docker-compose.random.yml
... ... @@ -14,13 +14,20 @@
14 14 # limitations under the License.
15 15 #
16 16
17   -version: '2'
18   -
19   -services:
20   - db:
21   - ports:
22   - - "9042"
23   - - "9160"
24   - zk:
25   - ports:
26   - - "2181"
  17 +---
  18 +apiVersion: storage.k8s.io/v1beta1
  19 +kind: StorageClass
  20 +metadata:
  21 + name: slow
  22 +provisioner: kubernetes.io/gce-pd
  23 +parameters:
  24 + type: pd-standard
  25 +---
  26 +apiVersion: storage.k8s.io/v1beta1
  27 +kind: StorageClass
  28 +metadata:
  29 + name: fast
  30 +provisioner: kubernetes.io/gce-pd
  31 +parameters:
  32 + type: pd-ssd
  33 +---
\ No newline at end of file
... ...
1   -#!/bin/bash
2   -#
3   -# Copyright © 2016-2017 The Thingsboard Authors
4   -#
5   -# Licensed under the Apache License, Version 2.0 (the "License");
6   -# you may not use this file except in compliance with the License.
7   -# You may obtain a copy of the License at
8   -#
9   -# http://www.apache.org/licenses/LICENSE-2.0
10   -#
11   -# Unless required by applicable law or agreed to in writing, software
12   -# distributed under the License is distributed on an "AS IS" BASIS,
13   -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   -# See the License for the specific language governing permissions and
15   -# limitations under the License.
16   -#
17   -
18   -
19   -command='docker-compose -f docker-compose.yml -f docker-compose.random.yml'
20   -
21   -echo "stopping images.."
22   -$command stop
23   -
24   -echo "removing stopped images.."
25   -$command rm -f
26   -
27   -echo "building images.."
28   -$command build
29   -
30   -echo "starting images..."
31   -$command up -d
1   -#!/bin/bash
2   -#
3   -# Copyright © 2016-2017 The Thingsboard Authors
4   -#
5   -# Licensed under the Apache License, Version 2.0 (the "License");
6   -# you may not use this file except in compliance with the License.
7   -# You may obtain a copy of the License at
8   -#
9   -# http://www.apache.org/licenses/LICENSE-2.0
10   -#
11   -# Unless required by applicable law or agreed to in writing, software
12   -# distributed under the License is distributed on an "AS IS" BASIS,
13   -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   -# See the License for the specific language governing permissions and
15   -# limitations under the License.
16   -#
17   -
18   -
19   -command='docker-compose -f docker-compose.yml -f docker-compose.static.yml'
20   -
21   -echo "stopping images.."
22   -$command stop
23   -
24   -echo "removing stopped images.."
25   -$command rm -f
26   -
27   -echo "building images.."
28   -$command build
29   -
30   -echo "starting cassandra, zookeeper, thingsboard-db-schema images..."
31   -$command up -d db zk thingsboard-db-schema