Commit d6ad8c9e55eb4b3343ad9640775878c5526487ad

Authored by Andrew Shvayka
2 parents 2435ca5d 90ef91e3

Merge with master

Showing 47 changed files with 2688 additions and 1072 deletions

Too many changes to show.

To preserve performance only 47 of 94 files are displayed.

@@ -21,6 +21,7 @@ import org.springframework.security.access.prepost.PreAuthorize; @@ -21,6 +21,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
21 import org.springframework.web.bind.annotation.*; 21 import org.springframework.web.bind.annotation.*;
22 import org.thingsboard.server.common.data.Customer; 22 import org.thingsboard.server.common.data.Customer;
23 import org.thingsboard.server.common.data.asset.Asset; 23 import org.thingsboard.server.common.data.asset.Asset;
  24 +import org.thingsboard.server.common.data.asset.TenantAssetType;
24 import org.thingsboard.server.common.data.id.AssetId; 25 import org.thingsboard.server.common.data.id.AssetId;
25 import org.thingsboard.server.common.data.id.CustomerId; 26 import org.thingsboard.server.common.data.id.CustomerId;
26 import org.thingsboard.server.common.data.id.TenantId; 27 import org.thingsboard.server.common.data.id.TenantId;
@@ -136,13 +137,18 @@ public class AssetController extends BaseController { @@ -136,13 +137,18 @@ public class AssetController extends BaseController {
136 @ResponseBody 137 @ResponseBody
137 public TextPageData<Asset> getTenantAssets( 138 public TextPageData<Asset> getTenantAssets(
138 @RequestParam int limit, 139 @RequestParam int limit,
  140 + @RequestParam(required = false) String type,
139 @RequestParam(required = false) String textSearch, 141 @RequestParam(required = false) String textSearch,
140 @RequestParam(required = false) String idOffset, 142 @RequestParam(required = false) String idOffset,
141 @RequestParam(required = false) String textOffset) throws ThingsboardException { 143 @RequestParam(required = false) String textOffset) throws ThingsboardException {
142 try { 144 try {
143 TenantId tenantId = getCurrentUser().getTenantId(); 145 TenantId tenantId = getCurrentUser().getTenantId();
144 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); 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 } catch (Exception e) { 152 } catch (Exception e) {
147 throw handleException(e); 153 throw handleException(e);
148 } 154 }
@@ -167,6 +173,7 @@ public class AssetController extends BaseController { @@ -167,6 +173,7 @@ public class AssetController extends BaseController {
167 public TextPageData<Asset> getCustomerAssets( 173 public TextPageData<Asset> getCustomerAssets(
168 @PathVariable("customerId") String strCustomerId, 174 @PathVariable("customerId") String strCustomerId,
169 @RequestParam int limit, 175 @RequestParam int limit,
  176 + @RequestParam(required = false) String type,
170 @RequestParam(required = false) String textSearch, 177 @RequestParam(required = false) String textSearch,
171 @RequestParam(required = false) String idOffset, 178 @RequestParam(required = false) String idOffset,
172 @RequestParam(required = false) String textOffset) throws ThingsboardException { 179 @RequestParam(required = false) String textOffset) throws ThingsboardException {
@@ -176,7 +183,11 @@ public class AssetController extends BaseController { @@ -176,7 +183,11 @@ public class AssetController extends BaseController {
176 CustomerId customerId = new CustomerId(toUUID(strCustomerId)); 183 CustomerId customerId = new CustomerId(toUUID(strCustomerId));
177 checkCustomerId(customerId); 184 checkCustomerId(customerId);
178 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); 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 } catch (Exception e) { 191 } catch (Exception e) {
181 throw handleException(e); 192 throw handleException(e);
182 } 193 }
@@ -231,4 +242,18 @@ public class AssetController extends BaseController { @@ -231,4 +242,18 @@ public class AssetController extends BaseController {
231 throw handleException(e); 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,6 +21,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
21 import org.springframework.web.bind.annotation.*; 21 import org.springframework.web.bind.annotation.*;
22 import org.thingsboard.server.common.data.Customer; 22 import org.thingsboard.server.common.data.Customer;
23 import org.thingsboard.server.common.data.Device; 23 import org.thingsboard.server.common.data.Device;
  24 +import org.thingsboard.server.common.data.TenantDeviceType;
24 import org.thingsboard.server.common.data.id.CustomerId; 25 import org.thingsboard.server.common.data.id.CustomerId;
25 import org.thingsboard.server.common.data.id.DeviceId; 26 import org.thingsboard.server.common.data.id.DeviceId;
26 import org.thingsboard.server.common.data.id.TenantId; 27 import org.thingsboard.server.common.data.id.TenantId;
@@ -166,13 +167,18 @@ public class DeviceController extends BaseController { @@ -166,13 +167,18 @@ public class DeviceController extends BaseController {
166 @ResponseBody 167 @ResponseBody
167 public TextPageData<Device> getTenantDevices( 168 public TextPageData<Device> getTenantDevices(
168 @RequestParam int limit, 169 @RequestParam int limit,
  170 + @RequestParam(required = false) String type,
169 @RequestParam(required = false) String textSearch, 171 @RequestParam(required = false) String textSearch,
170 @RequestParam(required = false) String idOffset, 172 @RequestParam(required = false) String idOffset,
171 @RequestParam(required = false) String textOffset) throws ThingsboardException { 173 @RequestParam(required = false) String textOffset) throws ThingsboardException {
172 try { 174 try {
173 TenantId tenantId = getCurrentUser().getTenantId(); 175 TenantId tenantId = getCurrentUser().getTenantId();
174 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); 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 } catch (Exception e) { 182 } catch (Exception e) {
177 throw handleException(e); 183 throw handleException(e);
178 } 184 }
@@ -197,6 +203,7 @@ public class DeviceController extends BaseController { @@ -197,6 +203,7 @@ public class DeviceController extends BaseController {
197 public TextPageData<Device> getCustomerDevices( 203 public TextPageData<Device> getCustomerDevices(
198 @PathVariable("customerId") String strCustomerId, 204 @PathVariable("customerId") String strCustomerId,
199 @RequestParam int limit, 205 @RequestParam int limit,
  206 + @RequestParam(required = false) String type,
200 @RequestParam(required = false) String textSearch, 207 @RequestParam(required = false) String textSearch,
201 @RequestParam(required = false) String idOffset, 208 @RequestParam(required = false) String idOffset,
202 @RequestParam(required = false) String textOffset) throws ThingsboardException { 209 @RequestParam(required = false) String textOffset) throws ThingsboardException {
@@ -206,7 +213,11 @@ public class DeviceController extends BaseController { @@ -206,7 +213,11 @@ public class DeviceController extends BaseController {
206 CustomerId customerId = new CustomerId(toUUID(strCustomerId)); 213 CustomerId customerId = new CustomerId(toUUID(strCustomerId));
207 checkCustomerId(customerId); 214 checkCustomerId(customerId);
208 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); 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 } catch (Exception e) { 221 } catch (Exception e) {
211 throw handleException(e); 222 throw handleException(e);
212 } 223 }
@@ -261,4 +272,19 @@ public class DeviceController extends BaseController { @@ -261,4 +272,19 @@ public class DeviceController extends BaseController {
261 throw handleException(e); 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 }
@@ -98,13 +98,15 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppC @@ -98,13 +98,15 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppC
98 @IntegrationTest("server.port:0") 98 @IntegrationTest("server.port:0")
99 public abstract class AbstractControllerTest { 99 public abstract class AbstractControllerTest {
100 100
  101 + protected static final String TEST_TENANT_NAME = "TEST TENANT";
  102 +
101 protected static final String SYS_ADMIN_EMAIL = "sysadmin@thingsboard.org"; 103 protected static final String SYS_ADMIN_EMAIL = "sysadmin@thingsboard.org";
102 private static final String SYS_ADMIN_PASSWORD = "sysadmin"; 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 private static final String TENANT_ADMIN_PASSWORD = "tenant"; 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 private static final String CUSTOMER_USER_PASSWORD = "customer"; 110 private static final String CUSTOMER_USER_PASSWORD = "customer";
109 111
110 protected MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(), 112 protected MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
@@ -147,7 +149,7 @@ public abstract class AbstractControllerTest { @@ -147,7 +149,7 @@ public abstract class AbstractControllerTest {
147 loginSysAdmin(); 149 loginSysAdmin();
148 150
149 Tenant tenant = new Tenant(); 151 Tenant tenant = new Tenant();
150 - tenant.setTitle("Tenant"); 152 + tenant.setTitle(TEST_TENANT_NAME);
151 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); 153 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
152 Assert.assertNotNull(savedTenant); 154 Assert.assertNotNull(savedTenant);
153 tenantId = savedTenant.getId(); 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,10 +24,7 @@ import java.util.Collections;
24 import java.util.List; 24 import java.util.List;
25 25
26 import org.apache.commons.lang3.RandomStringUtils; 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 import org.thingsboard.server.common.data.id.CustomerId; 28 import org.thingsboard.server.common.data.id.CustomerId;
32 import org.thingsboard.server.common.data.id.DeviceCredentialsId; 29 import org.thingsboard.server.common.data.id.DeviceCredentialsId;
33 import org.thingsboard.server.common.data.id.DeviceId; 30 import org.thingsboard.server.common.data.id.DeviceId;
@@ -83,6 +80,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -83,6 +80,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
83 public void testSaveDevice() throws Exception { 80 public void testSaveDevice() throws Exception {
84 Device device = new Device(); 81 Device device = new Device();
85 device.setName("My device"); 82 device.setName("My device");
  83 + device.setType("default");
86 Device savedDevice = doPost("/api/device", device, Device.class); 84 Device savedDevice = doPost("/api/device", device, Device.class);
87 85
88 Assert.assertNotNull(savedDevice); 86 Assert.assertNotNull(savedDevice);
@@ -114,16 +112,49 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -114,16 +112,49 @@ public class DeviceControllerTest extends AbstractControllerTest {
114 public void testFindDeviceById() throws Exception { 112 public void testFindDeviceById() throws Exception {
115 Device device = new Device(); 113 Device device = new Device();
116 device.setName("My device"); 114 device.setName("My device");
  115 + device.setType("default");
117 Device savedDevice = doPost("/api/device", device, Device.class); 116 Device savedDevice = doPost("/api/device", device, Device.class);
118 Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); 117 Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class);
119 Assert.assertNotNull(foundDevice); 118 Assert.assertNotNull(foundDevice);
120 Assert.assertEquals(savedDevice, foundDevice); 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 @Test 153 @Test
124 public void testDeleteDevice() throws Exception { 154 public void testDeleteDevice() throws Exception {
125 Device device = new Device(); 155 Device device = new Device();
126 device.setName("My device"); 156 device.setName("My device");
  157 + device.setType("default");
127 Device savedDevice = doPost("/api/device", device, Device.class); 158 Device savedDevice = doPost("/api/device", device, Device.class);
128 159
129 doDelete("/api/device/"+savedDevice.getId().getId().toString()) 160 doDelete("/api/device/"+savedDevice.getId().getId().toString())
@@ -132,10 +163,20 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -132,10 +163,20 @@ public class DeviceControllerTest extends AbstractControllerTest {
132 doGet("/api/device/"+savedDevice.getId().getId().toString()) 163 doGet("/api/device/"+savedDevice.getId().getId().toString())
133 .andExpect(status().isNotFound()); 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 @Test 176 @Test
137 public void testSaveDeviceWithEmptyName() throws Exception { 177 public void testSaveDeviceWithEmptyName() throws Exception {
138 Device device = new Device(); 178 Device device = new Device();
  179 + device.setType("default");
139 doPost("/api/device", device) 180 doPost("/api/device", device)
140 .andExpect(status().isBadRequest()) 181 .andExpect(status().isBadRequest())
141 .andExpect(statusReason(containsString("Device name should be specified"))); 182 .andExpect(statusReason(containsString("Device name should be specified")));
@@ -145,6 +186,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -145,6 +186,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
145 public void testAssignUnassignDeviceToCustomer() throws Exception { 186 public void testAssignUnassignDeviceToCustomer() throws Exception {
146 Device device = new Device(); 187 Device device = new Device();
147 device.setName("My device"); 188 device.setName("My device");
  189 + device.setType("default");
148 Device savedDevice = doPost("/api/device", device, Device.class); 190 Device savedDevice = doPost("/api/device", device, Device.class);
149 191
150 Customer customer = new Customer(); 192 Customer customer = new Customer();
@@ -170,6 +212,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -170,6 +212,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
170 public void testAssignDeviceToNonExistentCustomer() throws Exception { 212 public void testAssignDeviceToNonExistentCustomer() throws Exception {
171 Device device = new Device(); 213 Device device = new Device();
172 device.setName("My device"); 214 device.setName("My device");
  215 + device.setType("default");
173 Device savedDevice = doPost("/api/device", device, Device.class); 216 Device savedDevice = doPost("/api/device", device, Device.class);
174 217
175 doPost("/api/customer/" + UUIDs.timeBased().toString() 218 doPost("/api/customer/" + UUIDs.timeBased().toString()
@@ -203,6 +246,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -203,6 +246,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
203 246
204 Device device = new Device(); 247 Device device = new Device();
205 device.setName("My device"); 248 device.setName("My device");
  249 + device.setType("default");
206 Device savedDevice = doPost("/api/device", device, Device.class); 250 Device savedDevice = doPost("/api/device", device, Device.class);
207 251
208 doPost("/api/customer/" + savedCustomer.getId().getId().toString() 252 doPost("/api/customer/" + savedCustomer.getId().getId().toString()
@@ -219,6 +263,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -219,6 +263,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
219 public void testFindDeviceCredentialsByDeviceId() throws Exception { 263 public void testFindDeviceCredentialsByDeviceId() throws Exception {
220 Device device = new Device(); 264 Device device = new Device();
221 device.setName("My device"); 265 device.setName("My device");
  266 + device.setType("default");
222 Device savedDevice = doPost("/api/device", device, Device.class); 267 Device savedDevice = doPost("/api/device", device, Device.class);
223 DeviceCredentials deviceCredentials = 268 DeviceCredentials deviceCredentials =
224 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); 269 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -229,6 +274,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -229,6 +274,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
229 public void testSaveDeviceCredentials() throws Exception { 274 public void testSaveDeviceCredentials() throws Exception {
230 Device device = new Device(); 275 Device device = new Device();
231 device.setName("My device"); 276 device.setName("My device");
  277 + device.setType("default");
232 Device savedDevice = doPost("/api/device", device, Device.class); 278 Device savedDevice = doPost("/api/device", device, Device.class);
233 DeviceCredentials deviceCredentials = 279 DeviceCredentials deviceCredentials =
234 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); 280 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -255,6 +301,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -255,6 +301,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
255 public void testSaveDeviceCredentialsWithEmptyCredentialsType() throws Exception { 301 public void testSaveDeviceCredentialsWithEmptyCredentialsType() throws Exception {
256 Device device = new Device(); 302 Device device = new Device();
257 device.setName("My device"); 303 device.setName("My device");
  304 + device.setType("default");
258 Device savedDevice = doPost("/api/device", device, Device.class); 305 Device savedDevice = doPost("/api/device", device, Device.class);
259 DeviceCredentials deviceCredentials = 306 DeviceCredentials deviceCredentials =
260 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); 307 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -268,6 +315,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -268,6 +315,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
268 public void testSaveDeviceCredentialsWithEmptyCredentialsId() throws Exception { 315 public void testSaveDeviceCredentialsWithEmptyCredentialsId() throws Exception {
269 Device device = new Device(); 316 Device device = new Device();
270 device.setName("My device"); 317 device.setName("My device");
  318 + device.setType("default");
271 Device savedDevice = doPost("/api/device", device, Device.class); 319 Device savedDevice = doPost("/api/device", device, Device.class);
272 DeviceCredentials deviceCredentials = 320 DeviceCredentials deviceCredentials =
273 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); 321 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -281,6 +329,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -281,6 +329,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
281 public void testSaveNonExistentDeviceCredentials() throws Exception { 329 public void testSaveNonExistentDeviceCredentials() throws Exception {
282 Device device = new Device(); 330 Device device = new Device();
283 device.setName("My device"); 331 device.setName("My device");
  332 + device.setType("default");
284 Device savedDevice = doPost("/api/device", device, Device.class); 333 Device savedDevice = doPost("/api/device", device, Device.class);
285 DeviceCredentials deviceCredentials = 334 DeviceCredentials deviceCredentials =
286 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); 335 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -298,6 +347,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -298,6 +347,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
298 public void testSaveDeviceCredentialsWithNonExistentDevice() throws Exception { 347 public void testSaveDeviceCredentialsWithNonExistentDevice() throws Exception {
299 Device device = new Device(); 348 Device device = new Device();
300 device.setName("My device"); 349 device.setName("My device");
  350 + device.setType("default");
301 Device savedDevice = doPost("/api/device", device, Device.class); 351 Device savedDevice = doPost("/api/device", device, Device.class);
302 DeviceCredentials deviceCredentials = 352 DeviceCredentials deviceCredentials =
303 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); 353 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -307,9 +357,10 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -307,9 +357,10 @@ public class DeviceControllerTest extends AbstractControllerTest {
307 } 357 }
308 358
309 @Test 359 @Test
310 - public void testSaveDeviceCredentialsWithInvalidCredemtialsIdLength() throws Exception { 360 + public void testSaveDeviceCredentialsWithInvalidCredentialsIdLength() throws Exception {
311 Device device = new Device(); 361 Device device = new Device();
312 device.setName("My device"); 362 device.setName("My device");
  363 + device.setType("default");
313 Device savedDevice = doPost("/api/device", device, Device.class); 364 Device savedDevice = doPost("/api/device", device, Device.class);
314 DeviceCredentials deviceCredentials = 365 DeviceCredentials deviceCredentials =
315 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); 366 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -325,6 +376,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -325,6 +376,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
325 for (int i=0;i<178;i++) { 376 for (int i=0;i<178;i++) {
326 Device device = new Device(); 377 Device device = new Device();
327 device.setName("Device"+i); 378 device.setName("Device"+i);
  379 + device.setType("default");
328 devices.add(doPost("/api/device", device, Device.class)); 380 devices.add(doPost("/api/device", device, Device.class));
329 } 381 }
330 List<Device> loadedDevices = new ArrayList<>(); 382 List<Device> loadedDevices = new ArrayList<>();
@@ -355,6 +407,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -355,6 +407,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
355 String name = title1+suffix; 407 String name = title1+suffix;
356 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); 408 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
357 device.setName(name); 409 device.setName(name);
  410 + device.setType("default");
358 devicesTitle1.add(doPost("/api/device", device, Device.class)); 411 devicesTitle1.add(doPost("/api/device", device, Device.class));
359 } 412 }
360 String title2 = "Device title 2"; 413 String title2 = "Device title 2";
@@ -365,6 +418,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -365,6 +418,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
365 String name = title2+suffix; 418 String name = title2+suffix;
366 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); 419 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
367 device.setName(name); 420 device.setName(name);
  421 + device.setType("default");
368 devicesTitle2.add(doPost("/api/device", device, Device.class)); 422 devicesTitle2.add(doPost("/api/device", device, Device.class));
369 } 423 }
370 424
@@ -423,6 +477,89 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -423,6 +477,89 @@ public class DeviceControllerTest extends AbstractControllerTest {
423 Assert.assertFalse(pageData.hasNext()); 477 Assert.assertFalse(pageData.hasNext());
424 Assert.assertEquals(0, pageData.getData().size()); 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 @Test 564 @Test
428 public void testFindCustomerDevices() throws Exception { 565 public void testFindCustomerDevices() throws Exception {
@@ -435,6 +572,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -435,6 +572,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
435 for (int i=0;i<128;i++) { 572 for (int i=0;i<128;i++) {
436 Device device = new Device(); 573 Device device = new Device();
437 device.setName("Device"+i); 574 device.setName("Device"+i);
  575 + device.setType("default");
438 device = doPost("/api/device", device, Device.class); 576 device = doPost("/api/device", device, Device.class);
439 devices.add(doPost("/api/customer/" + customerId.getId().toString() 577 devices.add(doPost("/api/customer/" + customerId.getId().toString()
440 + "/device/" + device.getId().getId().toString(), Device.class)); 578 + "/device/" + device.getId().getId().toString(), Device.class));
@@ -473,6 +611,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -473,6 +611,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
473 String name = title1+suffix; 611 String name = title1+suffix;
474 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); 612 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
475 device.setName(name); 613 device.setName(name);
  614 + device.setType("default");
476 device = doPost("/api/device", device, Device.class); 615 device = doPost("/api/device", device, Device.class);
477 devicesTitle1.add(doPost("/api/customer/" + customerId.getId().toString() 616 devicesTitle1.add(doPost("/api/customer/" + customerId.getId().toString()
478 + "/device/" + device.getId().getId().toString(), Device.class)); 617 + "/device/" + device.getId().getId().toString(), Device.class));
@@ -485,6 +624,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -485,6 +624,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
485 String name = title2+suffix; 624 String name = title2+suffix;
486 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); 625 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
487 device.setName(name); 626 device.setName(name);
  627 + device.setType("default");
488 device = doPost("/api/device", device, Device.class); 628 device = doPost("/api/device", device, Device.class);
489 devicesTitle2.add(doPost("/api/customer/" + customerId.getId().toString() 629 devicesTitle2.add(doPost("/api/customer/" + customerId.getId().toString()
490 + "/device/" + device.getId().getId().toString(), Device.class)); 630 + "/device/" + device.getId().getId().toString(), Device.class));
@@ -546,4 +686,96 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -546,4 +686,96 @@ public class DeviceControllerTest extends AbstractControllerTest {
546 Assert.assertEquals(0, pageData.getData().size()); 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,7 +130,7 @@ public class TenantControllerTest extends AbstractControllerTest {
130 Assert.assertEquals(tenants, loadedTenants); 130 Assert.assertEquals(tenants, loadedTenants);
131 131
132 for (Tenant tenant : loadedTenants) { 132 for (Tenant tenant : loadedTenants) {
133 - if (!tenant.getTitle().equals("Tenant")) { 133 + if (!tenant.getTitle().equals(TEST_TENANT_NAME)) {
134 doDelete("/api/tenant/"+tenant.getId().getId().toString()) 134 doDelete("/api/tenant/"+tenant.getId().getId().toString())
135 .andExpect(status().isOk()); 135 .andExpect(status().isOk());
136 } 136 }
@@ -182,7 +182,7 @@ public class UserControllerTest extends AbstractControllerTest { @@ -182,7 +182,7 @@ public class UserControllerTest extends AbstractControllerTest {
182 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); 182 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
183 Assert.assertNotNull(savedTenant); 183 Assert.assertNotNull(savedTenant);
184 184
185 - String email = "tenant@thingsboard.org"; 185 + String email = TENANT_ADMIN_EMAIL;
186 User user = new User(); 186 User user = new User();
187 user.setAuthority(Authority.TENANT_ADMIN); 187 user.setAuthority(Authority.TENANT_ADMIN);
188 user.setTenantId(savedTenant.getId()); 188 user.setTenantId(savedTenant.getId());
@@ -47,6 +47,7 @@ public class HttpDeviceApiTest extends AbstractControllerTest { @@ -47,6 +47,7 @@ public class HttpDeviceApiTest extends AbstractControllerTest {
47 loginTenantAdmin(); 47 loginTenantAdmin();
48 device = new Device(); 48 device = new Device();
49 device.setName("My device"); 49 device.setName("My device");
  50 + device.setType("default");
50 device = doPost("/api/device", device, Device.class); 51 device = doPost("/api/device", device, Device.class);
51 52
52 deviceCredentials = 53 deviceCredentials =
  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 +}
  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 +}
@@ -16,12 +16,11 @@ @@ -16,12 +16,11 @@
16 package org.thingsboard.server.dao.asset; 16 package org.thingsboard.server.dao.asset;
17 17
18 import com.google.common.util.concurrent.ListenableFuture; 18 import com.google.common.util.concurrent.ListenableFuture;
19 -import org.thingsboard.server.common.data.Device;  
20 import org.thingsboard.server.common.data.asset.Asset; 19 import org.thingsboard.server.common.data.asset.Asset;
21 import org.thingsboard.server.common.data.page.TextPageLink; 20 import org.thingsboard.server.common.data.page.TextPageLink;
22 import org.thingsboard.server.dao.Dao; 21 import org.thingsboard.server.dao.Dao;
23 import org.thingsboard.server.dao.model.AssetEntity; 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 import java.util.List; 25 import java.util.List;
27 import java.util.Optional; 26 import java.util.Optional;
@@ -51,6 +50,16 @@ public interface AssetDao extends Dao<AssetEntity> { @@ -51,6 +50,16 @@ public interface AssetDao extends Dao<AssetEntity> {
51 List<AssetEntity> findAssetsByTenantId(UUID tenantId, TextPageLink pageLink); 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 * Find assets by tenantId and assets Ids. 63 * Find assets by tenantId and assets Ids.
55 * 64 *
56 * @param tenantId the tenantId 65 * @param tenantId the tenantId
@@ -70,6 +79,17 @@ public interface AssetDao extends Dao<AssetEntity> { @@ -70,6 +79,17 @@ public interface AssetDao extends Dao<AssetEntity> {
70 List<AssetEntity> findAssetsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink); 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 * Find assets by tenantId, customerId and assets Ids. 93 * Find assets by tenantId, customerId and assets Ids.
74 * 94 *
75 * @param tenantId the tenantId 95 * @param tenantId the tenantId
@@ -87,4 +107,12 @@ public interface AssetDao extends Dao<AssetEntity> { @@ -87,4 +107,12 @@ public interface AssetDao extends Dao<AssetEntity> {
87 * @return the optional asset object 107 * @return the optional asset object
88 */ 108 */
89 Optional<AssetEntity> findAssetsByTenantIdAndName(UUID tenantId, String name); 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,7 +15,12 @@
15 */ 15 */
16 package org.thingsboard.server.dao.asset; 16 package org.thingsboard.server.dao.asset;
17 17
  18 +import com.datastax.driver.core.ResultSet;
  19 +import com.datastax.driver.core.ResultSetFuture;
18 import com.datastax.driver.core.querybuilder.Select; 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 import com.google.common.util.concurrent.ListenableFuture; 24 import com.google.common.util.concurrent.ListenableFuture;
20 import lombok.extern.slf4j.Slf4j; 25 import lombok.extern.slf4j.Slf4j;
21 import org.springframework.stereotype.Component; 26 import org.springframework.stereotype.Component;
@@ -23,7 +28,9 @@ import org.thingsboard.server.common.data.asset.Asset; @@ -23,7 +28,9 @@ import org.thingsboard.server.common.data.asset.Asset;
23 import org.thingsboard.server.common.data.page.TextPageLink; 28 import org.thingsboard.server.common.data.page.TextPageLink;
24 import org.thingsboard.server.dao.AbstractSearchTextDao; 29 import org.thingsboard.server.dao.AbstractSearchTextDao;
25 import org.thingsboard.server.dao.model.AssetEntity; 30 import org.thingsboard.server.dao.model.AssetEntity;
  31 +import org.thingsboard.server.dao.model.TenantAssetTypeEntity;
26 32
  33 +import javax.annotation.Nullable;
27 import java.util.*; 34 import java.util.*;
28 35
29 import static com.datastax.driver.core.querybuilder.QueryBuilder.*; 36 import static com.datastax.driver.core.querybuilder.QueryBuilder.*;
@@ -60,6 +67,16 @@ public class AssetDaoImpl extends AbstractSearchTextDao<AssetEntity> implements @@ -60,6 +67,16 @@ public class AssetDaoImpl extends AbstractSearchTextDao<AssetEntity> implements
60 } 67 }
61 68
62 @Override 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 public ListenableFuture<List<AssetEntity>> findAssetsByTenantIdAndIdsAsync(UUID tenantId, List<UUID> assetIds) { 80 public ListenableFuture<List<AssetEntity>> findAssetsByTenantIdAndIdsAsync(UUID tenantId, List<UUID> assetIds) {
64 log.debug("Try to find assets by tenantId [{}] and asset Ids [{}]", tenantId, assetIds); 81 log.debug("Try to find assets by tenantId [{}] and asset Ids [{}]", tenantId, assetIds);
65 Select select = select().from(getColumnFamilyName()); 82 Select select = select().from(getColumnFamilyName());
@@ -82,6 +99,19 @@ public class AssetDaoImpl extends AbstractSearchTextDao<AssetEntity> implements @@ -82,6 +99,19 @@ public class AssetDaoImpl extends AbstractSearchTextDao<AssetEntity> implements
82 } 99 }
83 100
84 @Override 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 public ListenableFuture<List<AssetEntity>> findAssetsByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> assetIds) { 115 public ListenableFuture<List<AssetEntity>> findAssetsByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> assetIds) {
86 log.debug("Try to find assets by tenantId [{}], customerId [{}] and asset Ids [{}]", tenantId, customerId, assetIds); 116 log.debug("Try to find assets by tenantId [{}], customerId [{}] and asset Ids [{}]", tenantId, customerId, assetIds);
87 Select select = select().from(getColumnFamilyName()); 117 Select select = select().from(getColumnFamilyName());
@@ -101,4 +131,24 @@ public class AssetDaoImpl extends AbstractSearchTextDao<AssetEntity> implements @@ -101,4 +131,24 @@ public class AssetDaoImpl extends AbstractSearchTextDao<AssetEntity> implements
101 return Optional.ofNullable(findOneByStatement(query)); 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,6 +17,7 @@ package org.thingsboard.server.dao.asset;
17 17
18 import com.google.common.util.concurrent.ListenableFuture; 18 import com.google.common.util.concurrent.ListenableFuture;
19 import org.thingsboard.server.common.data.asset.Asset; 19 import org.thingsboard.server.common.data.asset.Asset;
  20 +import org.thingsboard.server.common.data.asset.TenantAssetType;
20 import org.thingsboard.server.common.data.id.AssetId; 21 import org.thingsboard.server.common.data.id.AssetId;
21 import org.thingsboard.server.common.data.id.CustomerId; 22 import org.thingsboard.server.common.data.id.CustomerId;
22 import org.thingsboard.server.common.data.id.TenantId; 23 import org.thingsboard.server.common.data.id.TenantId;
@@ -34,7 +35,7 @@ public interface AssetService { @@ -34,7 +35,7 @@ public interface AssetService {
34 35
35 Optional<Asset> findAssetByTenantIdAndName(TenantId tenantId, String name); 36 Optional<Asset> findAssetByTenantIdAndName(TenantId tenantId, String name);
36 37
37 - Asset saveAsset(Asset device); 38 + Asset saveAsset(Asset asset);
38 39
39 Asset assignAssetToCustomer(AssetId assetId, CustomerId customerId); 40 Asset assignAssetToCustomer(AssetId assetId, CustomerId customerId);
40 41
@@ -44,16 +45,21 @@ public interface AssetService { @@ -44,16 +45,21 @@ public interface AssetService {
44 45
45 TextPageData<Asset> findAssetsByTenantId(TenantId tenantId, TextPageLink pageLink); 46 TextPageData<Asset> findAssetsByTenantId(TenantId tenantId, TextPageLink pageLink);
46 47
  48 + TextPageData<Asset> findAssetsByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink);
  49 +
47 ListenableFuture<List<Asset>> findAssetsByTenantIdAndIdsAsync(TenantId tenantId, List<AssetId> assetIds); 50 ListenableFuture<List<Asset>> findAssetsByTenantIdAndIdsAsync(TenantId tenantId, List<AssetId> assetIds);
48 51
49 void deleteAssetsByTenantId(TenantId tenantId); 52 void deleteAssetsByTenantId(TenantId tenantId);
50 53
51 TextPageData<Asset> findAssetsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink); 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 ListenableFuture<List<Asset>> findAssetsByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<AssetId> assetIds); 58 ListenableFuture<List<Asset>> findAssetsByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<AssetId> assetIds);
54 59
55 void unassignCustomerAssets(TenantId tenantId, CustomerId customerId); 60 void unassignCustomerAssets(TenantId tenantId, CustomerId customerId);
56 61
57 ListenableFuture<List<Asset>> findAssetsByQuery(AssetSearchQuery query); 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,6 +26,7 @@ import org.springframework.stereotype.Service;
26 import org.springframework.util.StringUtils; 26 import org.springframework.util.StringUtils;
27 import org.thingsboard.server.common.data.EntityType; 27 import org.thingsboard.server.common.data.EntityType;
28 import org.thingsboard.server.common.data.asset.Asset; 28 import org.thingsboard.server.common.data.asset.Asset;
  29 +import org.thingsboard.server.common.data.asset.TenantAssetType;
29 import org.thingsboard.server.common.data.id.AssetId; 30 import org.thingsboard.server.common.data.id.AssetId;
30 import org.thingsboard.server.common.data.id.CustomerId; 31 import org.thingsboard.server.common.data.id.CustomerId;
31 import org.thingsboard.server.common.data.id.EntityId; 32 import org.thingsboard.server.common.data.id.EntityId;
@@ -36,10 +37,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation; @@ -36,10 +37,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation;
36 import org.thingsboard.server.dao.customer.CustomerDao; 37 import org.thingsboard.server.dao.customer.CustomerDao;
37 import org.thingsboard.server.dao.entity.BaseEntityService; 38 import org.thingsboard.server.dao.entity.BaseEntityService;
38 import org.thingsboard.server.dao.exception.DataValidationException; 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 import org.thingsboard.server.dao.relation.EntitySearchDirection; 41 import org.thingsboard.server.dao.relation.EntitySearchDirection;
44 import org.thingsboard.server.dao.service.DataValidator; 42 import org.thingsboard.server.dao.service.DataValidator;
45 import org.thingsboard.server.dao.service.PaginatedRemover; 43 import org.thingsboard.server.dao.service.PaginatedRemover;
@@ -132,7 +130,18 @@ public class BaseAssetService extends BaseEntityService implements AssetService @@ -132,7 +130,18 @@ public class BaseAssetService extends BaseEntityService implements AssetService
132 validatePageLink(pageLink, "Incorrect page link " + pageLink); 130 validatePageLink(pageLink, "Incorrect page link " + pageLink);
133 List<AssetEntity> assetEntities = assetDao.findAssetsByTenantId(tenantId.getId(), pageLink); 131 List<AssetEntity> assetEntities = assetDao.findAssetsByTenantId(tenantId.getId(), pageLink);
134 List<Asset> assets = convertDataList(assetEntities); 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 @Override 147 @Override
@@ -159,7 +168,19 @@ public class BaseAssetService extends BaseEntityService implements AssetService @@ -159,7 +168,19 @@ public class BaseAssetService extends BaseEntityService implements AssetService
159 validatePageLink(pageLink, "Incorrect page link " + pageLink); 168 validatePageLink(pageLink, "Incorrect page link " + pageLink);
160 List<AssetEntity> assetEntities = assetDao.findAssetsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); 169 List<AssetEntity> assetEntities = assetDao.findAssetsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink);
161 List<Asset> assets = convertDataList(assetEntities); 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 @Override 186 @Override
@@ -207,6 +228,25 @@ public class BaseAssetService extends BaseEntityService implements AssetService @@ -207,6 +228,25 @@ public class BaseAssetService extends BaseEntityService implements AssetService
207 return assets; 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 private DataValidator<Asset> assetValidator = 250 private DataValidator<Asset> assetValidator =
211 new DataValidator<Asset>() { 251 new DataValidator<Asset>() {
212 252
@@ -232,6 +272,9 @@ public class BaseAssetService extends BaseEntityService implements AssetService @@ -232,6 +272,9 @@ public class BaseAssetService extends BaseEntityService implements AssetService
232 272
233 @Override 273 @Override
234 protected void validateDataImpl(Asset asset) { 274 protected void validateDataImpl(Asset asset) {
  275 + if (StringUtils.isEmpty(asset.getType())) {
  276 + throw new DataValidationException("Asset type should be specified!");
  277 + }
235 if (StringUtils.isEmpty(asset.getName())) { 278 if (StringUtils.isEmpty(asset.getName())) {
236 throw new DataValidationException("Asset name should be specified!"); 279 throw new DataValidationException("Asset name should be specified!");
237 } 280 }
@@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.Device; @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.Device;
24 import org.thingsboard.server.common.data.page.TextPageLink; 24 import org.thingsboard.server.common.data.page.TextPageLink;
25 import org.thingsboard.server.dao.Dao; 25 import org.thingsboard.server.dao.Dao;
26 import org.thingsboard.server.dao.model.DeviceEntity; 26 import org.thingsboard.server.dao.model.DeviceEntity;
  27 +import org.thingsboard.server.dao.model.TenantDeviceTypeEntity;
27 28
28 /** 29 /**
29 * The Interface DeviceDao. 30 * The Interface DeviceDao.
@@ -49,6 +50,16 @@ public interface DeviceDao extends Dao<DeviceEntity> { @@ -49,6 +50,16 @@ public interface DeviceDao extends Dao<DeviceEntity> {
49 List<DeviceEntity> findDevicesByTenantId(UUID tenantId, TextPageLink pageLink); 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 * Find devices by tenantId and devices Ids. 63 * Find devices by tenantId and devices Ids.
53 * 64 *
54 * @param tenantId the tenantId 65 * @param tenantId the tenantId
@@ -68,6 +79,18 @@ public interface DeviceDao extends Dao<DeviceEntity> { @@ -68,6 +79,18 @@ public interface DeviceDao extends Dao<DeviceEntity> {
68 List<DeviceEntity> findDevicesByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink); 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 * Find devices by tenantId, customerId and devices Ids. 94 * Find devices by tenantId, customerId and devices Ids.
72 * 95 *
73 * @param tenantId the tenantId 96 * @param tenantId the tenantId
@@ -85,4 +108,11 @@ public interface DeviceDao extends Dao<DeviceEntity> { @@ -85,4 +108,11 @@ public interface DeviceDao extends Dao<DeviceEntity> {
85 * @return the optional device object 108 * @return the optional device object
86 */ 109 */
87 Optional<DeviceEntity> findDevicesByTenantIdAndName(UUID tenantId, String name); 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,7 +22,12 @@ import static org.thingsboard.server.dao.model.ModelConstants.*;
22 22
23 import java.util.*; 23 import java.util.*;
24 24
  25 +import com.datastax.driver.core.ResultSet;
  26 +import com.datastax.driver.core.ResultSetFuture;
25 import com.datastax.driver.core.querybuilder.Select; 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 import com.google.common.util.concurrent.ListenableFuture; 31 import com.google.common.util.concurrent.ListenableFuture;
27 import lombok.extern.slf4j.Slf4j; 32 import lombok.extern.slf4j.Slf4j;
28 import org.springframework.stereotype.Component; 33 import org.springframework.stereotype.Component;
@@ -32,6 +37,9 @@ import org.thingsboard.server.dao.AbstractSearchTextDao; @@ -32,6 +37,9 @@ import org.thingsboard.server.dao.AbstractSearchTextDao;
32 import org.thingsboard.server.dao.model.DeviceEntity; 37 import org.thingsboard.server.dao.model.DeviceEntity;
33 import org.slf4j.Logger; 38 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory; 39 import org.slf4j.LoggerFactory;
  40 +import org.thingsboard.server.dao.model.TenantDeviceTypeEntity;
  41 +
  42 +import javax.annotation.Nullable;
35 43
36 @Component 44 @Component
37 @Slf4j 45 @Slf4j
@@ -64,6 +72,16 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement @@ -64,6 +72,16 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement
64 } 72 }
65 73
66 @Override 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 public ListenableFuture<List<DeviceEntity>> findDevicesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> deviceIds) { 85 public ListenableFuture<List<DeviceEntity>> findDevicesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> deviceIds) {
68 log.debug("Try to find devices by tenantId [{}] and device Ids [{}]", tenantId, deviceIds); 86 log.debug("Try to find devices by tenantId [{}] and device Ids [{}]", tenantId, deviceIds);
69 Select select = select().from(getColumnFamilyName()); 87 Select select = select().from(getColumnFamilyName());
@@ -75,7 +93,7 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement @@ -75,7 +93,7 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement
75 93
76 @Override 94 @Override
77 public List<DeviceEntity> findDevicesByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) { 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 List<DeviceEntity> deviceEntities = findPageWithTextSearch(DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, 97 List<DeviceEntity> deviceEntities = findPageWithTextSearch(DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
80 Arrays.asList(eq(DEVICE_CUSTOMER_ID_PROPERTY, customerId), 98 Arrays.asList(eq(DEVICE_CUSTOMER_ID_PROPERTY, customerId),
81 eq(DEVICE_TENANT_ID_PROPERTY, tenantId)), 99 eq(DEVICE_TENANT_ID_PROPERTY, tenantId)),
@@ -86,6 +104,19 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement @@ -86,6 +104,19 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement
86 } 104 }
87 105
88 @Override 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 public ListenableFuture<List<DeviceEntity>> findDevicesByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> deviceIds) { 120 public ListenableFuture<List<DeviceEntity>> findDevicesByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> deviceIds) {
90 log.debug("Try to find devices by tenantId [{}], customerId [{}] and device Ids [{}]", tenantId, customerId, deviceIds); 121 log.debug("Try to find devices by tenantId [{}], customerId [{}] and device Ids [{}]", tenantId, customerId, deviceIds);
91 Select select = select().from(getColumnFamilyName()); 122 Select select = select().from(getColumnFamilyName());
@@ -105,4 +136,24 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement @@ -105,4 +136,24 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement
105 return Optional.ofNullable(findOneByStatement(query)); 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,6 +17,7 @@ package org.thingsboard.server.dao.device;
17 17
18 import com.google.common.util.concurrent.ListenableFuture; 18 import com.google.common.util.concurrent.ListenableFuture;
19 import org.thingsboard.server.common.data.Device; 19 import org.thingsboard.server.common.data.Device;
  20 +import org.thingsboard.server.common.data.TenantDeviceType;
20 import org.thingsboard.server.common.data.id.CustomerId; 21 import org.thingsboard.server.common.data.id.CustomerId;
21 import org.thingsboard.server.common.data.id.DeviceId; 22 import org.thingsboard.server.common.data.id.DeviceId;
22 import org.thingsboard.server.common.data.id.TenantId; 23 import org.thingsboard.server.common.data.id.TenantId;
@@ -44,16 +45,22 @@ public interface DeviceService { @@ -44,16 +45,22 @@ public interface DeviceService {
44 45
45 TextPageData<Device> findDevicesByTenantId(TenantId tenantId, TextPageLink pageLink); 46 TextPageData<Device> findDevicesByTenantId(TenantId tenantId, TextPageLink pageLink);
46 47
  48 + TextPageData<Device> findDevicesByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink);
  49 +
47 ListenableFuture<List<Device>> findDevicesByTenantIdAndIdsAsync(TenantId tenantId, List<DeviceId> deviceIds); 50 ListenableFuture<List<Device>> findDevicesByTenantIdAndIdsAsync(TenantId tenantId, List<DeviceId> deviceIds);
48 51
49 void deleteDevicesByTenantId(TenantId tenantId); 52 void deleteDevicesByTenantId(TenantId tenantId);
50 53
51 TextPageData<Device> findDevicesByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink); 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 ListenableFuture<List<Device>> findDevicesByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<DeviceId> deviceIds); 58 ListenableFuture<List<Device>> findDevicesByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<DeviceId> deviceIds);
54 59
55 void unassignCustomerDevices(TenantId tenantId, CustomerId customerId); 60 void unassignCustomerDevices(TenantId tenantId, CustomerId customerId);
56 61
57 ListenableFuture<List<Device>> findDevicesByQuery(DeviceSearchQuery query); 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,6 +26,7 @@ import org.springframework.stereotype.Service;
26 import org.springframework.util.StringUtils; 26 import org.springframework.util.StringUtils;
27 import org.thingsboard.server.common.data.Device; 27 import org.thingsboard.server.common.data.Device;
28 import org.thingsboard.server.common.data.EntityType; 28 import org.thingsboard.server.common.data.EntityType;
  29 +import org.thingsboard.server.common.data.TenantDeviceType;
29 import org.thingsboard.server.common.data.id.CustomerId; 30 import org.thingsboard.server.common.data.id.CustomerId;
30 import org.thingsboard.server.common.data.id.DeviceId; 31 import org.thingsboard.server.common.data.id.DeviceId;
31 import org.thingsboard.server.common.data.id.EntityId; 32 import org.thingsboard.server.common.data.id.EntityId;
@@ -40,6 +41,7 @@ import org.thingsboard.server.dao.entity.BaseEntityService; @@ -40,6 +41,7 @@ import org.thingsboard.server.dao.entity.BaseEntityService;
40 import org.thingsboard.server.dao.exception.DataValidationException; 41 import org.thingsboard.server.dao.exception.DataValidationException;
41 import org.thingsboard.server.dao.model.CustomerEntity; 42 import org.thingsboard.server.dao.model.CustomerEntity;
42 import org.thingsboard.server.dao.model.DeviceEntity; 43 import org.thingsboard.server.dao.model.DeviceEntity;
  44 +import org.thingsboard.server.dao.model.TenantDeviceTypeEntity;
43 import org.thingsboard.server.dao.model.TenantEntity; 45 import org.thingsboard.server.dao.model.TenantEntity;
44 import org.thingsboard.server.dao.relation.EntitySearchDirection; 46 import org.thingsboard.server.dao.relation.EntitySearchDirection;
45 import org.thingsboard.server.dao.service.DataValidator; 47 import org.thingsboard.server.dao.service.DataValidator;
@@ -47,9 +49,7 @@ import org.thingsboard.server.dao.service.PaginatedRemover; @@ -47,9 +49,7 @@ import org.thingsboard.server.dao.service.PaginatedRemover;
47 import org.thingsboard.server.dao.tenant.TenantDao; 49 import org.thingsboard.server.dao.tenant.TenantDao;
48 50
49 import javax.annotation.Nullable; 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 import java.util.stream.Collectors; 53 import java.util.stream.Collectors;
54 54
55 import static org.thingsboard.server.dao.DaoUtil.*; 55 import static org.thingsboard.server.dao.DaoUtil.*;
@@ -148,7 +148,18 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic @@ -148,7 +148,18 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic
148 validatePageLink(pageLink, "Incorrect page link " + pageLink); 148 validatePageLink(pageLink, "Incorrect page link " + pageLink);
149 List<DeviceEntity> deviceEntities = deviceDao.findDevicesByTenantId(tenantId.getId(), pageLink); 149 List<DeviceEntity> deviceEntities = deviceDao.findDevicesByTenantId(tenantId.getId(), pageLink);
150 List<Device> devices = convertDataList(deviceEntities); 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 @Override 165 @Override
@@ -176,7 +187,19 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic @@ -176,7 +187,19 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic
176 validatePageLink(pageLink, "Incorrect page link " + pageLink); 187 validatePageLink(pageLink, "Incorrect page link " + pageLink);
177 List<DeviceEntity> deviceEntities = deviceDao.findDevicesByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); 188 List<DeviceEntity> deviceEntities = deviceDao.findDevicesByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink);
178 List<Device> devices = convertDataList(deviceEntities); 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 @Override 205 @Override
@@ -224,6 +247,25 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic @@ -224,6 +247,25 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic
224 return devices; 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 private DataValidator<Device> deviceValidator = 269 private DataValidator<Device> deviceValidator =
228 new DataValidator<Device>() { 270 new DataValidator<Device>() {
229 271
@@ -249,6 +291,9 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic @@ -249,6 +291,9 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic
249 291
250 @Override 292 @Override
251 protected void validateDataImpl(Device device) { 293 protected void validateDataImpl(Device device) {
  294 + if (StringUtils.isEmpty(device.getType())) {
  295 + throw new DataValidationException("Device type should be specified!");
  296 + }
252 if (StringUtils.isEmpty(device.getName())) { 297 if (StringUtils.isEmpty(device.getName())) {
253 throw new DataValidationException("Device name should be specified!"); 298 throw new DataValidationException("Device name should be specified!");
254 } 299 }
@@ -49,12 +49,13 @@ public final class AssetEntity implements SearchTextEntity<Asset> { @@ -49,12 +49,13 @@ public final class AssetEntity implements SearchTextEntity<Asset> {
49 @Column(name = ASSET_CUSTOMER_ID_PROPERTY) 49 @Column(name = ASSET_CUSTOMER_ID_PROPERTY)
50 private UUID customerId; 50 private UUID customerId;
51 51
52 - @Column(name = ASSET_NAME_PROPERTY)  
53 - private String name;  
54 - 52 + @PartitionKey(value = 3)
55 @Column(name = ASSET_TYPE_PROPERTY) 53 @Column(name = ASSET_TYPE_PROPERTY)
56 private String type; 54 private String type;
57 55
  56 + @Column(name = ASSET_NAME_PROPERTY)
  57 + private String name;
  58 +
58 @Column(name = SEARCH_TEXT_PROPERTY) 59 @Column(name = SEARCH_TEXT_PROPERTY)
59 private String searchText; 60 private String searchText;
60 61
@@ -49,12 +49,13 @@ public final class DeviceEntity implements SearchTextEntity<Device> { @@ -49,12 +49,13 @@ public final class DeviceEntity implements SearchTextEntity<Device> {
49 @Column(name = DEVICE_CUSTOMER_ID_PROPERTY) 49 @Column(name = DEVICE_CUSTOMER_ID_PROPERTY)
50 private UUID customerId; 50 private UUID customerId;
51 51
52 - @Column(name = DEVICE_NAME_PROPERTY)  
53 - private String name;  
54 - 52 + @PartitionKey(value = 3)
55 @Column(name = DEVICE_TYPE_PROPERTY) 53 @Column(name = DEVICE_TYPE_PROPERTY)
56 private String type; 54 private String type;
57 55
  56 + @Column(name = DEVICE_NAME_PROPERTY)
  57 + private String name;
  58 +
58 @Column(name = SEARCH_TEXT_PROPERTY) 59 @Column(name = SEARCH_TEXT_PROPERTY)
59 private String searchText; 60 private String searchText;
60 61
@@ -124,8 +124,11 @@ public class ModelConstants { @@ -124,8 +124,11 @@ public class ModelConstants {
124 public static final String DEVICE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY; 124 public static final String DEVICE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
125 125
126 public static final String DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_and_search_text"; 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 public static final String DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_customer_and_search_text"; 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 public static final String DEVICE_BY_TENANT_AND_NAME_VIEW_NAME = "device_by_tenant_and_name"; 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 * Cassandra asset constants. 134 * Cassandra asset constants.
@@ -138,8 +141,11 @@ public class ModelConstants { @@ -138,8 +141,11 @@ public class ModelConstants {
138 public static final String ASSET_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY; 141 public static final String ASSET_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
139 142
140 public static final String ASSET_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_tenant_and_search_text"; 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 public static final String ASSET_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_customer_and_search_text"; 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 public static final String ASSET_BY_TENANT_AND_NAME_VIEW_NAME = "asset_by_tenant_and_name"; 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 * Cassandra alarm constants. 151 * Cassandra alarm 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 +}
@@ -149,66 +149,73 @@ VALUES ( @@ -149,66 +149,73 @@ VALUES (
149 149
150 /** Demo device **/ 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 VALUES ( 153 VALUES (
154 minTimeuuid ( '2016-11-01 01:02:05+0000' ), 154 minTimeuuid ( '2016-11-01 01:02:05+0000' ),
155 minTimeuuid ( '2016-11-01 01:02:01+0000' ), 155 minTimeuuid ( '2016-11-01 01:02:01+0000' ),
156 minTimeuuid ( '2016-11-01 01:02:03+0000' ), 156 minTimeuuid ( '2016-11-01 01:02:03+0000' ),
  157 + 'default',
157 'Test Device A1', 158 'Test Device A1',
158 'test device a1' 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 VALUES ( 163 VALUES (
163 minTimeuuid ( '2016-11-01 01:02:05+0001' ), 164 minTimeuuid ( '2016-11-01 01:02:05+0001' ),
164 minTimeuuid ( '2016-11-01 01:02:01+0000' ), 165 minTimeuuid ( '2016-11-01 01:02:01+0000' ),
165 minTimeuuid ( '2016-11-01 01:02:03+0000' ), 166 minTimeuuid ( '2016-11-01 01:02:03+0000' ),
  167 + 'default',
166 'Test Device A2', 168 'Test Device A2',
167 'test device a2' 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 VALUES ( 173 VALUES (
172 minTimeuuid ( '2016-11-01 01:02:05+0002' ), 174 minTimeuuid ( '2016-11-01 01:02:05+0002' ),
173 minTimeuuid ( '2016-11-01 01:02:01+0000' ), 175 minTimeuuid ( '2016-11-01 01:02:01+0000' ),
174 minTimeuuid ( '2016-11-01 01:02:03+0000' ), 176 minTimeuuid ( '2016-11-01 01:02:03+0000' ),
  177 + 'default',
175 'Test Device A3', 178 'Test Device A3',
176 'test device a3' 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 VALUES ( 183 VALUES (
181 minTimeuuid ( '2016-11-01 01:02:05+0003' ), 184 minTimeuuid ( '2016-11-01 01:02:05+0003' ),
182 minTimeuuid ( '2016-11-01 01:02:01+0000' ), 185 minTimeuuid ( '2016-11-01 01:02:01+0000' ),
183 minTimeuuid ( '2016-11-01 01:02:03+0001' ), 186 minTimeuuid ( '2016-11-01 01:02:03+0001' ),
  187 + 'default',
184 'Test Device B1', 188 'Test Device B1',
185 'test device b1' 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 VALUES ( 193 VALUES (
190 minTimeuuid ( '2016-11-01 01:02:05+0004' ), 194 minTimeuuid ( '2016-11-01 01:02:05+0004' ),
191 minTimeuuid ( '2016-11-01 01:02:01+0000' ), 195 minTimeuuid ( '2016-11-01 01:02:01+0000' ),
192 minTimeuuid ( '2016-11-01 01:02:03+0002' ), 196 minTimeuuid ( '2016-11-01 01:02:03+0002' ),
  197 + 'default',
193 'Test Device C1', 198 'Test Device C1',
194 'test device c1' 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 VALUES ( 203 VALUES (
199 c8f1a6f0-b993-11e6-8a04-9ff4e1b7933c, 204 c8f1a6f0-b993-11e6-8a04-9ff4e1b7933c,
200 minTimeuuid ( '2016-11-01 01:02:01+0000' ), 205 minTimeuuid ( '2016-11-01 01:02:01+0000' ),
201 minTimeuuid ( 0 ), 206 minTimeuuid ( 0 ),
  207 + 'default',
202 'DHT11 Demo Device', 208 'DHT11 Demo Device',
203 'dht11 demo device', 209 'dht11 demo device',
204 '{"description":"Demo device that is used in sample applications that upload data from DHT11 temperature and humidity sensor"}' 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 VALUES ( 214 VALUES (
209 c8f1a6f0-b993-11e6-8a04-9ff4e1b7933d, 215 c8f1a6f0-b993-11e6-8a04-9ff4e1b7933d,
210 minTimeuuid ( '2016-11-01 01:02:01+0000' ), 216 minTimeuuid ( '2016-11-01 01:02:01+0000' ),
211 minTimeuuid ( 0 ), 217 minTimeuuid ( 0 ),
  218 + 'default',
212 'Raspberry Pi Demo Device', 219 'Raspberry Pi Demo Device',
213 'raspberry pi demo device', 220 'raspberry pi demo device',
214 '{"description":"Demo device that is used in Raspberry Pi GPIO control sample application"}' 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,36 +152,57 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.customer_by_tenant_and_search
152 WITH CLUSTERING ORDER BY ( search_text ASC, id DESC ); 152 WITH CLUSTERING ORDER BY ( search_text ASC, id DESC );
153 153
154 CREATE TABLE IF NOT EXISTS thingsboard.device ( 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 CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_tenant_and_name AS 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 CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_tenant_and_search_text AS 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 CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_customer_and_search_text AS 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 CREATE TABLE IF NOT EXISTS thingsboard.device_credentials ( 207 CREATE TABLE IF NOT EXISTS thingsboard.device_credentials (
187 id timeuuid PRIMARY KEY, 208 id timeuuid PRIMARY KEY,
@@ -203,38 +224,58 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_credentials_by_credent @@ -203,38 +224,58 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_credentials_by_credent
203 WHERE credentials_id IS NOT NULL AND id IS NOT NULL 224 WHERE credentials_id IS NOT NULL AND id IS NOT NULL
204 PRIMARY KEY ( credentials_id, id ); 225 PRIMARY KEY ( credentials_id, id );
205 226
206 -  
207 CREATE TABLE IF NOT EXISTS thingsboard.asset ( 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 CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_tenant_and_name AS 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 CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_tenant_and_search_text AS 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 CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_customer_and_search_text AS 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 CREATE TABLE IF NOT EXISTS thingsboard.alarm ( 280 CREATE TABLE IF NOT EXISTS thingsboard.alarm (
240 id timeuuid, 281 id timeuuid,
@@ -32,7 +32,6 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -32,7 +32,6 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
32 import org.springframework.test.context.support.AnnotationConfigContextLoader; 32 import org.springframework.test.context.support.AnnotationConfigContextLoader;
33 import org.thingsboard.server.common.data.BaseData; 33 import org.thingsboard.server.common.data.BaseData;
34 import org.thingsboard.server.common.data.Event; 34 import org.thingsboard.server.common.data.Event;
35 -import org.thingsboard.server.common.data.alarm.AlarmStatus;  
36 import org.thingsboard.server.common.data.id.EntityId; 35 import org.thingsboard.server.common.data.id.EntityId;
37 import org.thingsboard.server.common.data.id.TenantId; 36 import org.thingsboard.server.common.data.id.TenantId;
38 import org.thingsboard.server.common.data.id.UUIDBased; 37 import org.thingsboard.server.common.data.id.UUIDBased;
@@ -42,6 +41,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType; @@ -42,6 +41,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
42 import org.thingsboard.server.common.data.plugin.PluginMetaData; 41 import org.thingsboard.server.common.data.plugin.PluginMetaData;
43 import org.thingsboard.server.common.data.rule.RuleMetaData; 42 import org.thingsboard.server.common.data.rule.RuleMetaData;
44 import org.thingsboard.server.dao.alarm.AlarmService; 43 import org.thingsboard.server.dao.alarm.AlarmService;
  44 +import org.thingsboard.server.dao.asset.AssetService;
45 import org.thingsboard.server.dao.component.ComponentDescriptorService; 45 import org.thingsboard.server.dao.component.ComponentDescriptorService;
46 import org.thingsboard.server.dao.customer.CustomerService; 46 import org.thingsboard.server.dao.customer.CustomerService;
47 import org.thingsboard.server.dao.dashboard.DashboardService; 47 import org.thingsboard.server.dao.dashboard.DashboardService;
@@ -90,6 +90,9 @@ public abstract class AbstractServiceTest { @@ -90,6 +90,9 @@ public abstract class AbstractServiceTest {
90 protected DeviceService deviceService; 90 protected DeviceService deviceService;
91 91
92 @Autowired 92 @Autowired
  93 + protected AssetService assetService;
  94 +
  95 + @Autowired
93 protected DeviceCredentialsService deviceCredentialsService; 96 protected DeviceCredentialsService deviceCredentialsService;
94 97
95 @Autowired 98 @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,6 +58,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest {
58 public void testSaveDeviceCredentialsWithEmptyDevice() { 58 public void testSaveDeviceCredentialsWithEmptyDevice() {
59 Device device = new Device(); 59 Device device = new Device();
60 device.setName("My device"); 60 device.setName("My device");
  61 + device.setType("default");
61 device.setTenantId(tenantId); 62 device.setTenantId(tenantId);
62 device = deviceService.saveDevice(device); 63 device = deviceService.saveDevice(device);
63 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getId()); 64 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getId());
@@ -73,6 +74,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest { @@ -73,6 +74,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest {
73 public void testSaveDeviceCredentialsWithEmptyCredentialsType() { 74 public void testSaveDeviceCredentialsWithEmptyCredentialsType() {
74 Device device = new Device(); 75 Device device = new Device();
75 device.setName("My device"); 76 device.setName("My device");
  77 + device.setType("default");
76 device.setTenantId(tenantId); 78 device.setTenantId(tenantId);
77 device = deviceService.saveDevice(device); 79 device = deviceService.saveDevice(device);
78 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getId()); 80 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getId());
@@ -88,6 +90,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest { @@ -88,6 +90,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest {
88 public void testSaveDeviceCredentialsWithEmptyCredentialsId() { 90 public void testSaveDeviceCredentialsWithEmptyCredentialsId() {
89 Device device = new Device(); 91 Device device = new Device();
90 device.setName("My device"); 92 device.setName("My device");
  93 + device.setType("default");
91 device.setTenantId(tenantId); 94 device.setTenantId(tenantId);
92 device = deviceService.saveDevice(device); 95 device = deviceService.saveDevice(device);
93 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getId()); 96 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getId());
@@ -103,6 +106,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest { @@ -103,6 +106,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest {
103 public void testSaveNonExistentDeviceCredentials() { 106 public void testSaveNonExistentDeviceCredentials() {
104 Device device = new Device(); 107 Device device = new Device();
105 device.setName("My device"); 108 device.setName("My device");
  109 + device.setType("default");
106 device.setTenantId(tenantId); 110 device.setTenantId(tenantId);
107 device = deviceService.saveDevice(device); 111 device = deviceService.saveDevice(device);
108 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getId()); 112 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getId());
@@ -122,6 +126,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest { @@ -122,6 +126,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest {
122 public void testSaveDeviceCredentialsWithNonExistentDevice() { 126 public void testSaveDeviceCredentialsWithNonExistentDevice() {
123 Device device = new Device(); 127 Device device = new Device();
124 device.setName("My device"); 128 device.setName("My device");
  129 + device.setType("default");
125 device.setTenantId(tenantId); 130 device.setTenantId(tenantId);
126 device = deviceService.saveDevice(device); 131 device = deviceService.saveDevice(device);
127 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getId()); 132 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getId());
@@ -137,6 +142,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest { @@ -137,6 +142,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest {
137 public void testSaveDeviceCredentialsWithInvalidCredemtialsIdLength() { 142 public void testSaveDeviceCredentialsWithInvalidCredemtialsIdLength() {
138 Device device = new Device(); 143 Device device = new Device();
139 device.setName("My device"); 144 device.setName("My device");
  145 + device.setType("default");
140 device.setTenantId(tenantId); 146 device.setTenantId(tenantId);
141 device = deviceService.saveDevice(device); 147 device = deviceService.saveDevice(device);
142 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getId()); 148 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getId());
@@ -153,6 +159,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest { @@ -153,6 +159,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest {
153 Device device = new Device(); 159 Device device = new Device();
154 device.setTenantId(tenantId); 160 device.setTenantId(tenantId);
155 device.setName("My device"); 161 device.setName("My device");
  162 + device.setType("default");
156 Device savedDevice = deviceService.saveDevice(device); 163 Device savedDevice = deviceService.saveDevice(device);
157 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedDevice.getId()); 164 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedDevice.getId());
158 Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId()); 165 Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId());
@@ -166,6 +173,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest { @@ -166,6 +173,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest {
166 Device device = new Device(); 173 Device device = new Device();
167 device.setTenantId(tenantId); 174 device.setTenantId(tenantId);
168 device.setName("My device"); 175 device.setName("My device");
  176 + device.setType("default");
169 Device savedDevice = deviceService.saveDevice(device); 177 Device savedDevice = deviceService.saveDevice(device);
170 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedDevice.getId()); 178 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedDevice.getId());
171 Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId()); 179 Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId());
@@ -181,6 +189,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest { @@ -181,6 +189,7 @@ public class DeviceCredentialsServiceImplTest extends AbstractServiceTest {
181 Device device = new Device(); 189 Device device = new Device();
182 device.setTenantId(tenantId); 190 device.setTenantId(tenantId);
183 device.setName("My device"); 191 device.setName("My device");
  192 + device.setType("default");
184 Device savedDevice = deviceService.saveDevice(device); 193 Device savedDevice = deviceService.saveDevice(device);
185 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedDevice.getId()); 194 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedDevice.getId());
186 Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId()); 195 Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId());
@@ -24,6 +24,7 @@ import org.junit.Test; @@ -24,6 +24,7 @@ import org.junit.Test;
24 import org.thingsboard.server.common.data.Customer; 24 import org.thingsboard.server.common.data.Customer;
25 import org.thingsboard.server.common.data.Device; 25 import org.thingsboard.server.common.data.Device;
26 import org.thingsboard.server.common.data.Tenant; 26 import org.thingsboard.server.common.data.Tenant;
  27 +import org.thingsboard.server.common.data.TenantDeviceType;
27 import org.thingsboard.server.common.data.id.CustomerId; 28 import org.thingsboard.server.common.data.id.CustomerId;
28 import org.thingsboard.server.common.data.id.DeviceCredentialsId; 29 import org.thingsboard.server.common.data.id.DeviceCredentialsId;
29 import org.thingsboard.server.common.data.id.DeviceId; 30 import org.thingsboard.server.common.data.id.DeviceId;
@@ -37,6 +38,7 @@ import org.thingsboard.server.dao.exception.DataValidationException; @@ -37,6 +38,7 @@ import org.thingsboard.server.dao.exception.DataValidationException;
37 import java.util.ArrayList; 38 import java.util.ArrayList;
38 import java.util.Collections; 39 import java.util.Collections;
39 import java.util.List; 40 import java.util.List;
  41 +import java.util.concurrent.Executors;
40 42
41 import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; 43 import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
42 44
@@ -65,6 +67,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest { @@ -65,6 +67,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
65 Device device = new Device(); 67 Device device = new Device();
66 device.setTenantId(tenantId); 68 device.setTenantId(tenantId);
67 device.setName("My device"); 69 device.setName("My device");
  70 + device.setType("default");
68 Device savedDevice = deviceService.saveDevice(device); 71 Device savedDevice = deviceService.saveDevice(device);
69 72
70 Assert.assertNotNull(savedDevice); 73 Assert.assertNotNull(savedDevice);
@@ -95,6 +98,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest { @@ -95,6 +98,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
95 @Test(expected = DataValidationException.class) 98 @Test(expected = DataValidationException.class)
96 public void testSaveDeviceWithEmptyName() { 99 public void testSaveDeviceWithEmptyName() {
97 Device device = new Device(); 100 Device device = new Device();
  101 + device.setType("default");
98 device.setTenantId(tenantId); 102 device.setTenantId(tenantId);
99 deviceService.saveDevice(device); 103 deviceService.saveDevice(device);
100 } 104 }
@@ -103,6 +107,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest { @@ -103,6 +107,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
103 public void testSaveDeviceWithEmptyTenant() { 107 public void testSaveDeviceWithEmptyTenant() {
104 Device device = new Device(); 108 Device device = new Device();
105 device.setName("My device"); 109 device.setName("My device");
  110 + device.setType("default");
106 deviceService.saveDevice(device); 111 deviceService.saveDevice(device);
107 } 112 }
108 113
@@ -110,6 +115,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest { @@ -110,6 +115,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
110 public void testSaveDeviceWithInvalidTenant() { 115 public void testSaveDeviceWithInvalidTenant() {
111 Device device = new Device(); 116 Device device = new Device();
112 device.setName("My device"); 117 device.setName("My device");
  118 + device.setType("default");
113 device.setTenantId(new TenantId(UUIDs.timeBased())); 119 device.setTenantId(new TenantId(UUIDs.timeBased()));
114 deviceService.saveDevice(device); 120 deviceService.saveDevice(device);
115 } 121 }
@@ -118,6 +124,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest { @@ -118,6 +124,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
118 public void testAssignDeviceToNonExistentCustomer() { 124 public void testAssignDeviceToNonExistentCustomer() {
119 Device device = new Device(); 125 Device device = new Device();
120 device.setName("My device"); 126 device.setName("My device");
  127 + device.setType("default");
121 device.setTenantId(tenantId); 128 device.setTenantId(tenantId);
122 device = deviceService.saveDevice(device); 129 device = deviceService.saveDevice(device);
123 try { 130 try {
@@ -131,6 +138,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest { @@ -131,6 +138,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
131 public void testAssignDeviceToCustomerFromDifferentTenant() { 138 public void testAssignDeviceToCustomerFromDifferentTenant() {
132 Device device = new Device(); 139 Device device = new Device();
133 device.setName("My device"); 140 device.setName("My device");
  141 + device.setType("default");
134 device.setTenantId(tenantId); 142 device.setTenantId(tenantId);
135 device = deviceService.saveDevice(device); 143 device = deviceService.saveDevice(device);
136 Tenant tenant = new Tenant(); 144 Tenant tenant = new Tenant();
@@ -153,18 +161,56 @@ public class DeviceServiceImplTest extends AbstractServiceTest { @@ -153,18 +161,56 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
153 Device device = new Device(); 161 Device device = new Device();
154 device.setTenantId(tenantId); 162 device.setTenantId(tenantId);
155 device.setName("My device"); 163 device.setName("My device");
  164 + device.setType("default");
156 Device savedDevice = deviceService.saveDevice(device); 165 Device savedDevice = deviceService.saveDevice(device);
157 Device foundDevice = deviceService.findDeviceById(savedDevice.getId()); 166 Device foundDevice = deviceService.findDeviceById(savedDevice.getId());
158 Assert.assertNotNull(foundDevice); 167 Assert.assertNotNull(foundDevice);
159 Assert.assertEquals(savedDevice, foundDevice); 168 Assert.assertEquals(savedDevice, foundDevice);
160 deviceService.deleteDevice(savedDevice.getId()); 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 @Test 208 @Test
164 public void testDeleteDevice() { 209 public void testDeleteDevice() {
165 Device device = new Device(); 210 Device device = new Device();
166 device.setTenantId(tenantId); 211 device.setTenantId(tenantId);
167 device.setName("My device"); 212 device.setName("My device");
  213 + device.setType("default");
168 Device savedDevice = deviceService.saveDevice(device); 214 Device savedDevice = deviceService.saveDevice(device);
169 Device foundDevice = deviceService.findDeviceById(savedDevice.getId()); 215 Device foundDevice = deviceService.findDeviceById(savedDevice.getId());
170 Assert.assertNotNull(foundDevice); 216 Assert.assertNotNull(foundDevice);
@@ -188,6 +234,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest { @@ -188,6 +234,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
188 Device device = new Device(); 234 Device device = new Device();
189 device.setTenantId(tenantId); 235 device.setTenantId(tenantId);
190 device.setName("Device"+i); 236 device.setName("Device"+i);
  237 + device.setType("default");
191 devices.add(deviceService.saveDevice(device)); 238 devices.add(deviceService.saveDevice(device));
192 } 239 }
193 240
@@ -216,7 +263,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest { @@ -216,7 +263,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
216 263
217 tenantService.deleteTenant(tenantId); 264 tenantService.deleteTenant(tenantId);
218 } 265 }
219 - 266 +
220 @Test 267 @Test
221 public void testFindDevicesByTenantIdAndName() { 268 public void testFindDevicesByTenantIdAndName() {
222 String title1 = "Device title 1"; 269 String title1 = "Device title 1";
@@ -228,6 +275,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest { @@ -228,6 +275,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
228 String name = title1+suffix; 275 String name = title1+suffix;
229 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); 276 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
230 device.setName(name); 277 device.setName(name);
  278 + device.setType("default");
231 devicesTitle1.add(deviceService.saveDevice(device)); 279 devicesTitle1.add(deviceService.saveDevice(device));
232 } 280 }
233 String title2 = "Device title 2"; 281 String title2 = "Device title 2";
@@ -239,6 +287,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest { @@ -239,6 +287,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
239 String name = title2+suffix; 287 String name = title2+suffix;
240 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); 288 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
241 device.setName(name); 289 device.setName(name);
  290 + device.setType("default");
242 devicesTitle2.add(deviceService.saveDevice(device)); 291 devicesTitle2.add(deviceService.saveDevice(device));
243 } 292 }
244 293
@@ -291,6 +340,85 @@ public class DeviceServiceImplTest extends AbstractServiceTest { @@ -291,6 +340,85 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
291 Assert.assertFalse(pageData.hasNext()); 340 Assert.assertFalse(pageData.hasNext());
292 Assert.assertEquals(0, pageData.getData().size()); 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 @Test 423 @Test
296 public void testFindDevicesByTenantIdAndCustomerId() { 424 public void testFindDevicesByTenantIdAndCustomerId() {
@@ -311,6 +439,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest { @@ -311,6 +439,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
311 Device device = new Device(); 439 Device device = new Device();
312 device.setTenantId(tenantId); 440 device.setTenantId(tenantId);
313 device.setName("Device"+i); 441 device.setName("Device"+i);
  442 + device.setType("default");
314 device = deviceService.saveDevice(device); 443 device = deviceService.saveDevice(device);
315 devices.add(deviceService.assignDeviceToCustomer(device.getId(), customerId)); 444 devices.add(deviceService.assignDeviceToCustomer(device.getId(), customerId));
316 } 445 }
@@ -359,6 +488,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest { @@ -359,6 +488,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
359 String name = title1+suffix; 488 String name = title1+suffix;
360 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); 489 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
361 device.setName(name); 490 device.setName(name);
  491 + device.setType("default");
362 device = deviceService.saveDevice(device); 492 device = deviceService.saveDevice(device);
363 devicesTitle1.add(deviceService.assignDeviceToCustomer(device.getId(), customerId)); 493 devicesTitle1.add(deviceService.assignDeviceToCustomer(device.getId(), customerId));
364 } 494 }
@@ -371,6 +501,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest { @@ -371,6 +501,7 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
371 String name = title2+suffix; 501 String name = title2+suffix;
372 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); 502 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
373 device.setName(name); 503 device.setName(name);
  504 + device.setType("default");
374 device = deviceService.saveDevice(device); 505 device = deviceService.saveDevice(device);
375 devicesTitle2.add(deviceService.assignDeviceToCustomer(device.getId(), customerId)); 506 devicesTitle2.add(deviceService.assignDeviceToCustomer(device.getId(), customerId));
376 } 507 }
@@ -425,4 +556,94 @@ public class DeviceServiceImplTest extends AbstractServiceTest { @@ -425,4 +556,94 @@ public class DeviceServiceImplTest extends AbstractServiceTest {
425 Assert.assertEquals(0, pageData.getData().size()); 556 Assert.assertEquals(0, pageData.getData().size());
426 customerService.deleteCustomer(customerId); 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 }
@@ -31,7 +31,8 @@ function AssetService($http, $q, customerService, userService) { @@ -31,7 +31,8 @@ function AssetService($http, $q, customerService, userService) {
31 getTenantAssets: getTenantAssets, 31 getTenantAssets: getTenantAssets,
32 getCustomerAssets: getCustomerAssets, 32 getCustomerAssets: getCustomerAssets,
33 findByQuery: findByQuery, 33 findByQuery: findByQuery,
34 - fetchAssetsByNameFilter: fetchAssetsByNameFilter 34 + fetchAssetsByNameFilter: fetchAssetsByNameFilter,
  35 + getAssetTypes: getAssetTypes
35 } 36 }
36 37
37 return service; 38 return service;
@@ -152,7 +153,7 @@ function AssetService($http, $q, customerService, userService) { @@ -152,7 +153,7 @@ function AssetService($http, $q, customerService, userService) {
152 return deferred.promise; 153 return deferred.promise;
153 } 154 }
154 155
155 - function getTenantAssets(pageLink, applyCustomersInfo, config) { 156 + function getTenantAssets(pageLink, applyCustomersInfo, config, type) {
156 var deferred = $q.defer(); 157 var deferred = $q.defer();
157 var url = '/api/tenant/assets?limit=' + pageLink.limit; 158 var url = '/api/tenant/assets?limit=' + pageLink.limit;
158 if (angular.isDefined(pageLink.textSearch)) { 159 if (angular.isDefined(pageLink.textSearch)) {
@@ -164,6 +165,9 @@ function AssetService($http, $q, customerService, userService) { @@ -164,6 +165,9 @@ function AssetService($http, $q, customerService, userService) {
164 if (angular.isDefined(pageLink.textOffset)) { 165 if (angular.isDefined(pageLink.textOffset)) {
165 url += '&textOffset=' + pageLink.textOffset; 166 url += '&textOffset=' + pageLink.textOffset;
166 } 167 }
  168 + if (angular.isDefined(type) && type.length) {
  169 + url += '&type=' + type;
  170 + }
167 $http.get(url, config).then(function success(response) { 171 $http.get(url, config).then(function success(response) {
168 if (applyCustomersInfo) { 172 if (applyCustomersInfo) {
169 customerService.applyAssignedCustomersInfo(response.data.data).then( 173 customerService.applyAssignedCustomersInfo(response.data.data).then(
@@ -184,7 +188,7 @@ function AssetService($http, $q, customerService, userService) { @@ -184,7 +188,7 @@ function AssetService($http, $q, customerService, userService) {
184 return deferred.promise; 188 return deferred.promise;
185 } 189 }
186 190
187 - function getCustomerAssets(customerId, pageLink, applyCustomersInfo, config) { 191 + function getCustomerAssets(customerId, pageLink, applyCustomersInfo, config, type) {
188 var deferred = $q.defer(); 192 var deferred = $q.defer();
189 var url = '/api/customer/' + customerId + '/assets?limit=' + pageLink.limit; 193 var url = '/api/customer/' + customerId + '/assets?limit=' + pageLink.limit;
190 if (angular.isDefined(pageLink.textSearch)) { 194 if (angular.isDefined(pageLink.textSearch)) {
@@ -196,6 +200,9 @@ function AssetService($http, $q, customerService, userService) { @@ -196,6 +200,9 @@ function AssetService($http, $q, customerService, userService) {
196 if (angular.isDefined(pageLink.textOffset)) { 200 if (angular.isDefined(pageLink.textOffset)) {
197 url += '&textOffset=' + pageLink.textOffset; 201 url += '&textOffset=' + pageLink.textOffset;
198 } 202 }
  203 + if (angular.isDefined(type) && type.length) {
  204 + url += '&type=' + type;
  205 + }
199 $http.get(url, config).then(function success(response) { 206 $http.get(url, config).then(function success(response) {
200 if (applyCustomersInfo) { 207 if (applyCustomersInfo) {
201 customerService.applyAssignedCustomerInfo(response.data.data, customerId).then( 208 customerService.applyAssignedCustomerInfo(response.data.data, customerId).then(
@@ -258,4 +265,15 @@ function AssetService($http, $q, customerService, userService) { @@ -258,4 +265,15 @@ function AssetService($http, $q, customerService, userService) {
258 return deferred.promise; 265 return deferred.promise;
259 } 266 }
260 267
  268 + function getAssetTypes() {
  269 + var deferred = $q.defer();
  270 + var url = '/api/asset/types';
  271 + $http.get(url).then(function success(response) {
  272 + deferred.resolve(response.data);
  273 + }, function fail() {
  274 + deferred.reject();
  275 + });
  276 + return deferred.promise;
  277 + }
  278 +
261 } 279 }
@@ -41,12 +41,13 @@ function DeviceService($http, $q, attributeService, customerService, types) { @@ -41,12 +41,13 @@ function DeviceService($http, $q, attributeService, customerService, types) {
41 deleteDeviceAttributes: deleteDeviceAttributes, 41 deleteDeviceAttributes: deleteDeviceAttributes,
42 sendOneWayRpcCommand: sendOneWayRpcCommand, 42 sendOneWayRpcCommand: sendOneWayRpcCommand,
43 sendTwoWayRpcCommand: sendTwoWayRpcCommand, 43 sendTwoWayRpcCommand: sendTwoWayRpcCommand,
44 - findByQuery: findByQuery 44 + findByQuery: findByQuery,
  45 + getDeviceTypes: getDeviceTypes
45 } 46 }
46 47
47 return service; 48 return service;
48 49
49 - function getTenantDevices(pageLink, applyCustomersInfo, config) { 50 + function getTenantDevices(pageLink, applyCustomersInfo, config, type) {
50 var deferred = $q.defer(); 51 var deferred = $q.defer();
51 var url = '/api/tenant/devices?limit=' + pageLink.limit; 52 var url = '/api/tenant/devices?limit=' + pageLink.limit;
52 if (angular.isDefined(pageLink.textSearch)) { 53 if (angular.isDefined(pageLink.textSearch)) {
@@ -58,6 +59,9 @@ function DeviceService($http, $q, attributeService, customerService, types) { @@ -58,6 +59,9 @@ function DeviceService($http, $q, attributeService, customerService, types) {
58 if (angular.isDefined(pageLink.textOffset)) { 59 if (angular.isDefined(pageLink.textOffset)) {
59 url += '&textOffset=' + pageLink.textOffset; 60 url += '&textOffset=' + pageLink.textOffset;
60 } 61 }
  62 + if (angular.isDefined(type) && type.length) {
  63 + url += '&type=' + type;
  64 + }
61 $http.get(url, config).then(function success(response) { 65 $http.get(url, config).then(function success(response) {
62 if (applyCustomersInfo) { 66 if (applyCustomersInfo) {
63 customerService.applyAssignedCustomersInfo(response.data.data).then( 67 customerService.applyAssignedCustomersInfo(response.data.data).then(
@@ -78,7 +82,7 @@ function DeviceService($http, $q, attributeService, customerService, types) { @@ -78,7 +82,7 @@ function DeviceService($http, $q, attributeService, customerService, types) {
78 return deferred.promise; 82 return deferred.promise;
79 } 83 }
80 84
81 - function getCustomerDevices(customerId, pageLink, applyCustomersInfo, config) { 85 + function getCustomerDevices(customerId, pageLink, applyCustomersInfo, config, type) {
82 var deferred = $q.defer(); 86 var deferred = $q.defer();
83 var url = '/api/customer/' + customerId + '/devices?limit=' + pageLink.limit; 87 var url = '/api/customer/' + customerId + '/devices?limit=' + pageLink.limit;
84 if (angular.isDefined(pageLink.textSearch)) { 88 if (angular.isDefined(pageLink.textSearch)) {
@@ -90,6 +94,9 @@ function DeviceService($http, $q, attributeService, customerService, types) { @@ -90,6 +94,9 @@ function DeviceService($http, $q, attributeService, customerService, types) {
90 if (angular.isDefined(pageLink.textOffset)) { 94 if (angular.isDefined(pageLink.textOffset)) {
91 url += '&textOffset=' + pageLink.textOffset; 95 url += '&textOffset=' + pageLink.textOffset;
92 } 96 }
  97 + if (angular.isDefined(type) && type.length) {
  98 + url += '&type=' + type;
  99 + }
93 $http.get(url, config).then(function success(response) { 100 $http.get(url, config).then(function success(response) {
94 if (applyCustomersInfo) { 101 if (applyCustomersInfo) {
95 customerService.applyAssignedCustomerInfo(response.data.data, customerId).then( 102 customerService.applyAssignedCustomerInfo(response.data.data, customerId).then(
@@ -286,4 +293,15 @@ function DeviceService($http, $q, attributeService, customerService, types) { @@ -286,4 +293,15 @@ function DeviceService($http, $q, attributeService, customerService, types) {
286 return deferred.promise; 293 return deferred.promise;
287 } 294 }
288 295
  296 + function getDeviceTypes() {
  297 + var deferred = $q.defer();
  298 + var url = '/api/device/types';
  299 + $http.get(url).then(function success(response) {
  300 + deferred.resolve(response.data);
  301 + }, function fail() {
  302 + deferred.reject();
  303 + });
  304 + return deferred.promise;
  305 + }
  306 +
289 } 307 }
@@ -36,7 +36,8 @@ function EntityService($http, $q, $filter, $translate, userService, deviceServic @@ -36,7 +36,8 @@ function EntityService($http, $q, $filter, $translate, userService, deviceServic
36 saveRelatedEntity: saveRelatedEntity, 36 saveRelatedEntity: saveRelatedEntity,
37 getRelatedEntity: getRelatedEntity, 37 getRelatedEntity: getRelatedEntity,
38 deleteRelatedEntity: deleteRelatedEntity, 38 deleteRelatedEntity: deleteRelatedEntity,
39 - moveEntity: moveEntity 39 + moveEntity: moveEntity,
  40 + copyEntity: copyEntity
40 }; 41 };
41 42
42 return service; 43 return service;
@@ -626,6 +627,32 @@ function EntityService($http, $q, $filter, $translate, userService, deviceServic @@ -626,6 +627,32 @@ function EntityService($http, $q, $filter, $translate, userService, deviceServic
626 return deferred.promise; 627 return deferred.promise;
627 } 628 }
628 629
  630 + function copyEntity(entity, targetParentId, keys) {
  631 + var deferred = $q.defer();
  632 + if (!entity.id && !entity.id.id) {
  633 + deferred.reject();
  634 + } else {
  635 + getRelatedEntity(entity.id, keys).then(
  636 + function success(relatedEntity) {
  637 + delete relatedEntity.id.id;
  638 + relatedEntity.name = entity.name;
  639 + saveRelatedEntity(relatedEntity, targetParentId, keys).then(
  640 + function success(savedEntity) {
  641 + deferred.resolve(savedEntity);
  642 + },
  643 + function fail() {
  644 + deferred.reject();
  645 + }
  646 + );
  647 + },
  648 + function fail() {
  649 + deferred.reject();
  650 + }
  651 + );
  652 + }
  653 + return deferred.promise;
  654 + }
  655 +
629 function saveEntityPromise(entity) { 656 function saveEntityPromise(entity) {
630 var entityType = entity.id.entityType; 657 var entityType = entity.id.entityType;
631 if (!entity.id.id) { 658 if (!entity.id.id) {
@@ -160,10 +160,6 @@ export default function AppConfig($provide, @@ -160,10 +160,6 @@ export default function AppConfig($provide,
160 indigoTheme(); 160 indigoTheme();
161 } 161 }
162 162
163 - $mdThemingProvider.theme('tb-search-input', 'default')  
164 - .primaryPalette('tb-primary')  
165 - .backgroundPalette('tb-primary');  
166 -  
167 $mdThemingProvider.setDefaultTheme('default'); 163 $mdThemingProvider.setDefaultTheme('default');
168 //$mdThemingProvider.alwaysWatchTheme(true); 164 //$mdThemingProvider.alwaysWatchTheme(true);
169 } 165 }
@@ -15,5 +15,8 @@ @@ -15,5 +15,8 @@
15 limitations under the License. 15 limitations under the License.
16 16
17 --> 17 -->
18 -<div class="tb-small" ng-show="vm.isAssignedToCustomer()">{{'asset.assignedToCustomer' | translate}} '{{vm.item.assignedCustomer.title}}'</div>  
19 -<div class="tb-small" ng-show="vm.isPublic()">{{'asset.public' | translate}}</div> 18 +<div flex layout="column" style="margin-top: -10px;">
  19 + <div flex style="text-transform: uppercase; padding-bottom: 10px;">{{vm.item.type}}</div>
  20 + <div class="tb-small" ng-show="vm.isAssignedToCustomer()">{{'asset.assignedToCustomer' | translate}} '{{vm.item.assignedCustomer.title}}'</div>
  21 + <div class="tb-small" ng-show="vm.isPublic()">{{'asset.public' | translate}}</div>
  22 +</div>
@@ -56,13 +56,13 @@ @@ -56,13 +56,13 @@
56 <div translate ng-message="required">asset.name-required</div> 56 <div translate ng-message="required">asset.name-required</div>
57 </div> 57 </div>
58 </md-input-container> 58 </md-input-container>
59 - <md-input-container class="md-block">  
60 - <label translate>asset.type</label>  
61 - <input required name="type" ng-model="asset.type">  
62 - <div ng-messages="theForm.name.$error">  
63 - <div translate ng-message="required">asset.type-required</div>  
64 - </div>  
65 - </md-input-container> 59 + <tb-entity-subtype-autocomplete
  60 + ng-disabled="loading || !isEdit"
  61 + tb-required="true"
  62 + the-form="theForm"
  63 + ng-model="asset.type"
  64 + entity-type="types.entityType.asset">
  65 + </tb-entity-subtype-autocomplete>
66 <md-input-container class="md-block"> 66 <md-input-container class="md-block">
67 <label translate>asset.description</label> 67 <label translate>asset.description</label>
68 <textarea ng-model="asset.additionalInfo.description" rows="2"></textarea> 68 <textarea ng-model="asset.additionalInfo.description" rows="2"></textarea>
@@ -47,7 +47,8 @@ export function AssetCardController(types) { @@ -47,7 +47,8 @@ export function AssetCardController(types) {
47 47
48 48
49 /*@ngInject*/ 49 /*@ngInject*/
50 -export function AssetController(userService, assetService, customerService, $state, $stateParams, $document, $mdDialog, $q, $translate, types) { 50 +export function AssetController($rootScope, userService, assetService, customerService, $state, $stateParams,
  51 + $document, $mdDialog, $q, $translate, types) {
51 52
52 var customerId = $stateParams.customerId; 53 var customerId = $stateParams.customerId;
53 54
@@ -129,8 +130,8 @@ export function AssetController(userService, assetService, customerService, $sta @@ -129,8 +130,8 @@ export function AssetController(userService, assetService, customerService, $sta
129 } 130 }
130 131
131 if (vm.assetsScope === 'tenant') { 132 if (vm.assetsScope === 'tenant') {
132 - fetchAssetsFunction = function (pageLink) {  
133 - return assetService.getTenantAssets(pageLink, true); 133 + fetchAssetsFunction = function (pageLink, assetType) {
  134 + return assetService.getTenantAssets(pageLink, true, null, assetType);
134 }; 135 };
135 deleteAssetFunction = function (assetId) { 136 deleteAssetFunction = function (assetId) {
136 return assetService.deleteAsset(assetId); 137 return assetService.deleteAsset(assetId);
@@ -229,8 +230,8 @@ export function AssetController(userService, assetService, customerService, $sta @@ -229,8 +230,8 @@ export function AssetController(userService, assetService, customerService, $sta
229 230
230 231
231 } else if (vm.assetsScope === 'customer' || vm.assetsScope === 'customer_user') { 232 } else if (vm.assetsScope === 'customer' || vm.assetsScope === 'customer_user') {
232 - fetchAssetsFunction = function (pageLink) {  
233 - return assetService.getCustomerAssets(customerId, pageLink, true); 233 + fetchAssetsFunction = function (pageLink, assetType) {
  234 + return assetService.getCustomerAssets(customerId, pageLink, true, null, assetType);
234 }; 235 };
235 deleteAssetFunction = function (assetId) { 236 deleteAssetFunction = function (assetId) {
236 return assetService.unassignAssetFromCustomer(assetId); 237 return assetService.unassignAssetFromCustomer(assetId);
@@ -333,6 +334,7 @@ export function AssetController(userService, assetService, customerService, $sta @@ -333,6 +334,7 @@ export function AssetController(userService, assetService, customerService, $sta
333 var deferred = $q.defer(); 334 var deferred = $q.defer();
334 assetService.saveAsset(asset).then( 335 assetService.saveAsset(asset).then(
335 function success(savedAsset) { 336 function success(savedAsset) {
  337 + $rootScope.$broadcast('assetSaved');
336 var assets = [ savedAsset ]; 338 var assets = [ savedAsset ];
337 customerService.applyAssignedCustomersInfo(assets).then( 339 customerService.applyAssignedCustomersInfo(assets).then(
338 function success(items) { 340 function success(items) {
@@ -25,6 +25,7 @@ export default function AssetDirective($compile, $templateCache, toast, $transla @@ -25,6 +25,7 @@ export default function AssetDirective($compile, $templateCache, toast, $transla
25 var template = $templateCache.get(assetFieldsetTemplate); 25 var template = $templateCache.get(assetFieldsetTemplate);
26 element.html(template); 26 element.html(template);
27 27
  28 + scope.types = types;
28 scope.isAssignedToCustomer = false; 29 scope.isAssignedToCustomer = false;
29 scope.isPublic = false; 30 scope.isPublic = false;
30 scope.assignedCustomer = null; 31 scope.assignedCustomer = null;
@@ -20,7 +20,7 @@ import assetsTemplate from './assets.tpl.html'; @@ -20,7 +20,7 @@ import assetsTemplate from './assets.tpl.html';
20 /* eslint-enable import/no-unresolved, import/default */ 20 /* eslint-enable import/no-unresolved, import/default */
21 21
22 /*@ngInject*/ 22 /*@ngInject*/
23 -export default function AssetRoutes($stateProvider) { 23 +export default function AssetRoutes($stateProvider, types) {
24 $stateProvider 24 $stateProvider
25 .state('home.assets', { 25 .state('home.assets', {
26 url: '/assets', 26 url: '/assets',
@@ -37,6 +37,8 @@ export default function AssetRoutes($stateProvider) { @@ -37,6 +37,8 @@ export default function AssetRoutes($stateProvider) {
37 data: { 37 data: {
38 assetsType: 'tenant', 38 assetsType: 'tenant',
39 searchEnabled: true, 39 searchEnabled: true,
  40 + searchByEntitySubtype: true,
  41 + searchEntityType: types.entityType.asset,
40 pageTitle: 'asset.assets' 42 pageTitle: 'asset.assets'
41 }, 43 },
42 ncyBreadcrumb: { 44 ncyBreadcrumb: {
@@ -58,6 +60,8 @@ export default function AssetRoutes($stateProvider) { @@ -58,6 +60,8 @@ export default function AssetRoutes($stateProvider) {
58 data: { 60 data: {
59 assetsType: 'customer', 61 assetsType: 'customer',
60 searchEnabled: true, 62 searchEnabled: true,
  63 + searchByEntitySubtype: true,
  64 + searchEntityType: types.entityType.asset,
61 pageTitle: 'customer.assets' 65 pageTitle: 'customer.assets'
62 }, 66 },
63 ncyBreadcrumb: { 67 ncyBreadcrumb: {
@@ -179,6 +179,7 @@ function DashboardUtils(types, utils, timeService) { @@ -179,6 +179,7 @@ function DashboardUtils(types, utils, timeService) {
179 dashboard.configuration.settings.showEntitiesSelect = true; 179 dashboard.configuration.settings.showEntitiesSelect = true;
180 dashboard.configuration.settings.showDashboardTimewindow = true; 180 dashboard.configuration.settings.showDashboardTimewindow = true;
181 dashboard.configuration.settings.showDashboardExport = true; 181 dashboard.configuration.settings.showDashboardExport = true;
  182 + dashboard.configuration.settings.toolbarAlwaysOpen = false;
182 } else { 183 } else {
183 if (angular.isUndefined(dashboard.configuration.settings.stateControllerId)) { 184 if (angular.isUndefined(dashboard.configuration.settings.stateControllerId)) {
184 dashboard.configuration.settings.stateControllerId = 'default'; 185 dashboard.configuration.settings.stateControllerId = 'default';
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 -import './datasource-device.scss';  
17 -  
18 -import 'md-color-picker';  
19 -import tinycolor from 'tinycolor2';  
20 -import $ from 'jquery';  
21 -import thingsboardTypes from '../common/types.constant';  
22 -import thingsboardDatakeyConfigDialog from './datakey-config-dialog.controller';  
23 -import thingsboardTruncate from './truncate.filter';  
24 -  
25 -/* eslint-disable import/no-unresolved, import/default */  
26 -  
27 -import datasourceDeviceTemplate from './datasource-device.tpl.html';  
28 -import datakeyConfigDialogTemplate from './datakey-config-dialog.tpl.html';  
29 -  
30 -/* eslint-enable import/no-unresolved, import/default */  
31 -  
32 -/* eslint-disable angular/angularelement */  
33 -  
34 -export default angular.module('thingsboard.directives.datasourceDevice', [thingsboardTruncate, thingsboardTypes, thingsboardDatakeyConfigDialog])  
35 - .directive('tbDatasourceDevice', DatasourceDevice)  
36 - .name;  
37 -  
38 -/*@ngInject*/  
39 -function DatasourceDevice($compile, $templateCache, $q, $mdDialog, $window, $document, $mdColorPicker, $mdConstant, types) {  
40 -  
41 - var linker = function (scope, element, attrs, ngModelCtrl) {  
42 - var template = $templateCache.get(datasourceDeviceTemplate);  
43 - element.html(template);  
44 -  
45 - scope.ngModelCtrl = ngModelCtrl;  
46 - scope.types = types;  
47 -  
48 - scope.selectedTimeseriesDataKey = null;  
49 - scope.timeseriesDataKeySearchText = null;  
50 -  
51 - scope.selectedAttributeDataKey = null;  
52 - scope.attributeDataKeySearchText = null;  
53 -  
54 - scope.updateValidity = function () {  
55 - if (ngModelCtrl.$viewValue) {  
56 - var value = ngModelCtrl.$viewValue;  
57 - var dataValid = angular.isDefined(value) && value != null;  
58 - ngModelCtrl.$setValidity('deviceData', dataValid);  
59 - if (dataValid) {  
60 - ngModelCtrl.$setValidity('deviceAlias',  
61 - angular.isDefined(value.deviceAliasId) &&  
62 - value.deviceAliasId != null);  
63 - ngModelCtrl.$setValidity('deviceKeys',  
64 - angular.isDefined(value.dataKeys) &&  
65 - value.dataKeys != null &&  
66 - value.dataKeys.length > 0);  
67 - }  
68 - }  
69 - };  
70 -  
71 - scope.$watch('deviceAlias', function () {  
72 - if (ngModelCtrl.$viewValue) {  
73 - if (scope.deviceAlias) {  
74 - ngModelCtrl.$viewValue.deviceAliasId = scope.deviceAlias.id;  
75 - } else {  
76 - ngModelCtrl.$viewValue.deviceAliasId = null;  
77 - }  
78 - scope.updateValidity();  
79 - scope.selectedDeviceAliasChange();  
80 - }  
81 - });  
82 -  
83 - scope.$watch('timeseriesDataKeys', function () {  
84 - if (ngModelCtrl.$viewValue) {  
85 - var dataKeys = [];  
86 - dataKeys = dataKeys.concat(scope.timeseriesDataKeys);  
87 - dataKeys = dataKeys.concat(scope.attributeDataKeys);  
88 - ngModelCtrl.$viewValue.dataKeys = dataKeys;  
89 - scope.updateValidity();  
90 - }  
91 - }, true);  
92 -  
93 - scope.$watch('attributeDataKeys', function () {  
94 - if (ngModelCtrl.$viewValue) {  
95 - var dataKeys = [];  
96 - dataKeys = dataKeys.concat(scope.timeseriesDataKeys);  
97 - dataKeys = dataKeys.concat(scope.attributeDataKeys);  
98 - ngModelCtrl.$viewValue.dataKeys = dataKeys;  
99 - scope.updateValidity();  
100 - }  
101 - }, true);  
102 -  
103 - ngModelCtrl.$render = function () {  
104 - if (ngModelCtrl.$viewValue) {  
105 - var deviceAliasId = ngModelCtrl.$viewValue.deviceAliasId;  
106 - if (scope.deviceAliases[deviceAliasId]) {  
107 - scope.deviceAlias = {id: deviceAliasId, alias: scope.deviceAliases[deviceAliasId].alias,  
108 - deviceId: scope.deviceAliases[deviceAliasId].deviceId};  
109 - } else {  
110 - scope.deviceAlias = null;  
111 - }  
112 - var timeseriesDataKeys = [];  
113 - var attributeDataKeys = [];  
114 - for (var d in ngModelCtrl.$viewValue.dataKeys) {  
115 - var dataKey = ngModelCtrl.$viewValue.dataKeys[d];  
116 - if (dataKey.type === types.dataKeyType.timeseries) {  
117 - timeseriesDataKeys.push(dataKey);  
118 - } else if (dataKey.type === types.dataKeyType.attribute) {  
119 - attributeDataKeys.push(dataKey);  
120 - }  
121 - }  
122 - scope.timeseriesDataKeys = timeseriesDataKeys;  
123 - scope.attributeDataKeys = attributeDataKeys;  
124 - }  
125 - };  
126 -  
127 - scope.textIsNotEmpty = function(text) {  
128 - return (text && text != null && text.length > 0) ? true : false;  
129 - }  
130 -  
131 - scope.selectedDeviceAliasChange = function () {  
132 - if (!scope.timeseriesDataKeySearchText || scope.timeseriesDataKeySearchText === '') {  
133 - scope.timeseriesDataKeySearchText = scope.timeseriesDataKeySearchText === '' ? null : '';  
134 - }  
135 - if (!scope.attributeDataKeySearchText || scope.attributeDataKeySearchText === '') {  
136 - scope.attributeDataKeySearchText = scope.attributeDataKeySearchText === '' ? null : '';  
137 - }  
138 - };  
139 -  
140 - scope.transformTimeseriesDataKeyChip = function (chip) {  
141 - return scope.generateDataKey({chip: chip, type: types.dataKeyType.timeseries});  
142 - };  
143 -  
144 - scope.transformAttributeDataKeyChip = function (chip) {  
145 - return scope.generateDataKey({chip: chip, type: types.dataKeyType.attribute});  
146 - };  
147 -  
148 - scope.showColorPicker = function (event, dataKey) {  
149 - $mdColorPicker.show({  
150 - value: dataKey.color,  
151 - defaultValue: '#fff',  
152 - random: tinycolor.random(),  
153 - clickOutsideToClose: false,  
154 - hasBackdrop: false,  
155 - skipHide: true,  
156 - preserveScope: false,  
157 -  
158 - mdColorAlphaChannel: true,  
159 - mdColorSpectrum: true,  
160 - mdColorSliders: true,  
161 - mdColorGenericPalette: false,  
162 - mdColorMaterialPalette: true,  
163 - mdColorHistory: false,  
164 - mdColorDefaultTab: 2,  
165 -  
166 - $event: event  
167 -  
168 - }).then(function (color) {  
169 - dataKey.color = color;  
170 - ngModelCtrl.$setDirty();  
171 - });  
172 - }  
173 -  
174 - scope.editDataKey = function (event, dataKey, index) {  
175 -  
176 - $mdDialog.show({  
177 - controller: 'DatakeyConfigDialogController',  
178 - controllerAs: 'vm',  
179 - templateUrl: datakeyConfigDialogTemplate,  
180 - locals: {  
181 - dataKey: angular.copy(dataKey),  
182 - dataKeySettingsSchema: scope.datakeySettingsSchema,  
183 - deviceAlias: scope.deviceAlias,  
184 - deviceAliases: scope.deviceAliases  
185 - },  
186 - parent: angular.element($document[0].body),  
187 - fullscreen: true,  
188 - targetEvent: event,  
189 - skipHide: true,  
190 - onComplete: function () {  
191 - var w = angular.element($window);  
192 - w.triggerHandler('resize');  
193 - }  
194 - }).then(function (dataKey) {  
195 - if (dataKey.type === types.dataKeyType.timeseries) {  
196 - scope.timeseriesDataKeys[index] = dataKey;  
197 - } else if (dataKey.type === types.dataKeyType.attribute) {  
198 - scope.attributeDataKeys[index] = dataKey;  
199 - }  
200 - ngModelCtrl.$setDirty();  
201 - }, function () {  
202 - });  
203 - };  
204 -  
205 - scope.dataKeysSearch = function (searchText, type) {  
206 - if (scope.deviceAlias) {  
207 - var deferred = $q.defer();  
208 - scope.fetchDeviceKeys({deviceAliasId: scope.deviceAlias.id, query: searchText, type: type})  
209 - .then(function (dataKeys) {  
210 - deferred.resolve(dataKeys);  
211 - }, function (e) {  
212 - deferred.reject(e);  
213 - });  
214 - return deferred.promise;  
215 - } else {  
216 - return $q.when([]);  
217 - }  
218 - };  
219 -  
220 - scope.createKey = function (event, chipsId) {  
221 - var chipsChild = $(chipsId, element)[0].firstElementChild;  
222 - var el = angular.element(chipsChild);  
223 - var chipBuffer = el.scope().$mdChipsCtrl.getChipBuffer();  
224 - event.preventDefault();  
225 - event.stopPropagation();  
226 - el.scope().$mdChipsCtrl.appendChip(chipBuffer.trim());  
227 - el.scope().$mdChipsCtrl.resetChipBuffer();  
228 - }  
229 -  
230 - $compile(element.contents())(scope);  
231 - }  
232 -  
233 - return {  
234 - restrict: "E",  
235 - require: "^ngModel",  
236 - scope: {  
237 - widgetType: '=',  
238 - deviceAliases: '=',  
239 - datakeySettingsSchema: '=',  
240 - generateDataKey: '&',  
241 - fetchDeviceKeys: '&',  
242 - onCreateDeviceAlias: '&'  
243 - },  
244 - link: linker  
245 - };  
246 -}  
247 -  
248 -/* eslint-enable angular/angularelement */  
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 -@import '../../scss/constants';  
17 -  
18 -.tb-device-alias-autocomplete, .tb-timeseries-datakey-autocomplete, .tb-attribute-datakey-autocomplete {  
19 - .tb-not-found {  
20 - display: block;  
21 - line-height: 1.5;  
22 - height: 48px;  
23 - .tb-no-entries {  
24 - line-height: 48px;  
25 - }  
26 - }  
27 - li {  
28 - height: auto !important;  
29 - white-space: normal !important;  
30 - }  
31 -}  
32 -  
33 -tb-datasource-device {  
34 - @media (min-width: $layout-breakpoint-gt-sm) {  
35 - padding-left: 4px;  
36 - padding-right: 4px;  
37 - }  
38 - tb-device-alias-select {  
39 - @media (min-width: $layout-breakpoint-gt-sm) {  
40 - width: 200px;  
41 - max-width: 200px;  
42 - }  
43 - }  
44 -}  
1 -<!--  
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 -<section flex layout='column' layout-align="center" layout-gt-sm='row' layout-align-gt-sm="start center">  
19 - <tb-device-alias-select  
20 - tb-required="true"  
21 - device-aliases="deviceAliases"  
22 - ng-model="deviceAlias"  
23 - on-create-device-alias="onCreateDeviceAlias({event: event, alias: alias})">  
24 - </tb-device-alias-select>  
25 - <section flex layout='column'>  
26 - <section flex layout='column' layout-align="center" style="padding-left: 4px;">  
27 - <md-chips flex  
28 - id="timeseries_datakey_chips"  
29 - ng-required="true"  
30 - ng-model="timeseriesDataKeys" md-autocomplete-snap  
31 - md-transform-chip="transformTimeseriesDataKeyChip($chip)"  
32 - md-require-match="false">  
33 - <md-autocomplete  
34 - md-no-cache="true"  
35 - id="timeseries_datakey"  
36 - md-selected-item="selectedTimeseriesDataKey"  
37 - md-search-text="timeseriesDataKeySearchText"  
38 - md-items="item in dataKeysSearch(timeseriesDataKeySearchText, types.dataKeyType.timeseries)"  
39 - md-item-text="item.name"  
40 - md-min-length="0"  
41 - placeholder="{{'datakey.timeseries' | translate }}"  
42 - md-menu-class="tb-timeseries-datakey-autocomplete">  
43 - <span md-highlight-text="timeseriesDataKeySearchText" md-highlight-flags="^i">{{item}}</span>  
44 - <md-not-found>  
45 - <div class="tb-not-found">  
46 - <div class="tb-no-entries" ng-if="!textIsNotEmpty(timeseriesDataKeySearchText)">  
47 - <span translate>device.no-keys-found</span>  
48 - </div>  
49 - <div ng-if="textIsNotEmpty(timeseriesDataKeySearchText)">  
50 - <span translate translate-values='{ key: "{{timeseriesDataKeySearchText | truncate:true:6:&apos;...&apos;}}" }'>device.no-key-matching</span>  
51 - <span>  
52 - <a translate ng-click="createKey($event, '#timeseries_datakey_chips')">device.create-new-key</a>  
53 - </span>  
54 - </div>  
55 - </div>  
56 - </md-not-found>  
57 - </md-autocomplete>  
58 - <md-chip-template>  
59 - <div layout="row" layout-align="start center" class="tb-attribute-chip">  
60 - <div class="tb-color-preview" ng-click="showColorPicker($event, $chip, $index)" style="margin-right: 5px;">  
61 - <div class="tb-color-result" ng-style="{background: $chip.color}"></div>  
62 - </div>  
63 - <div layout="row" flex>  
64 - <div class="tb-chip-label">  
65 - {{$chip.label}}  
66 - </div>  
67 - <div class="tb-chip-separator">: </div>  
68 - <div class="tb-chip-label">  
69 - <strong ng-if="!$chip.postFuncBody">{{$chip.name}}</strong>  
70 - <strong ng-if="$chip.postFuncBody">f({{$chip.name}})</strong>  
71 - </div>  
72 - </div>  
73 - <md-button ng-click="editDataKey($event, $chip, $index)" class="md-icon-button tb-md-32">  
74 - <md-icon aria-label="edit" class="material-icons tb-md-20">edit</md-icon>  
75 - </md-button>  
76 - </div>  
77 - </md-chip-template>  
78 - </md-chips>  
79 - <md-chips flex ng-if="widgetType === types.widgetType.latest.value"  
80 - id="attribute_datakey_chips"  
81 - ng-required="true"  
82 - ng-model="attributeDataKeys" md-autocomplete-snap  
83 - md-transform-chip="transformAttributeDataKeyChip($chip)"  
84 - md-require-match="false">  
85 - <md-autocomplete  
86 - md-no-cache="true"  
87 - id="attribute_datakey"  
88 - md-selected-item="selectedAttributeDataKey"  
89 - md-search-text="attributeDataKeySearchText"  
90 - md-items="item in dataKeysSearch(attributeDataKeySearchText, types.dataKeyType.attribute)"  
91 - md-item-text="item.name"  
92 - md-min-length="0"  
93 - placeholder="{{'datakey.attributes' | translate }}"  
94 - md-menu-class="tb-attribute-datakey-autocomplete">  
95 - <span md-highlight-text="attributeDataKeySearchText" md-highlight-flags="^i">{{item}}</span>  
96 - <md-not-found>  
97 - <div class="tb-not-found">  
98 - <div class="tb-no-entries" ng-if="!textIsNotEmpty(attributeDataKeySearchText)">  
99 - <span translate>device.no-keys-found</span>  
100 - </div>  
101 - <div ng-if="textIsNotEmpty(attributeDataKeySearchText)">  
102 - <span translate translate-values='{ key: "{{attributeDataKeySearchText | truncate:true:6:&apos;...&apos;}}" }'>device.no-key-matching</span>  
103 - <span>  
104 - <a translate ng-click="createKey($event, '#attribute_datakey_chips')">device.create-new-key</a>  
105 - </span>  
106 - </div>  
107 - </div>  
108 - </md-not-found>  
109 - </md-autocomplete>  
110 - <md-chip-template>  
111 - <div layout="row" layout-align="start center" class="tb-attribute-chip">  
112 - <div class="tb-color-preview" ng-click="showColorPicker($event, $chip, $index)" style="margin-right: 5px;">  
113 - <div class="tb-color-result" ng-style="{background: $chip.color}"></div>  
114 - </div>  
115 - <div layout="row" flex>  
116 - <div class="tb-chip-label">  
117 - {{$chip.label}}  
118 - </div>  
119 - <div class="tb-chip-separator">: </div>  
120 - <div class="tb-chip-label">  
121 - <strong ng-if="!$chip.postFuncBody">{{$chip.name}}</strong>  
122 - <strong ng-if="$chip.postFuncBody">f({{$chip.name}})</strong>  
123 - </div>  
124 - </div>  
125 - <md-button ng-click="editDataKey($event, $chip, $index)" class="md-icon-button tb-md-32">  
126 - <md-icon aria-label="edit" class="material-icons tb-md-20">edit</md-icon>  
127 - </md-button>  
128 - </div>  
129 - </md-chip-template>  
130 - </md-chips>  
131 - </section>  
132 - <div class="tb-error-messages" ng-messages="ngModelCtrl.$error" role="alert">  
133 - <div translate ng-message="deviceKeys" ng-if="widgetType === types.widgetType.timeseries.value" class="tb-error-message">datakey.timeseries-required</div>  
134 - <div translate ng-message="deviceKeys" ng-if="widgetType === types.widgetType.latest.value" class="tb-error-message">datakey.timeseries-or-attributes-required</div>  
135 - </div>  
136 - </section>  
137 -</section>  
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 -import $ from 'jquery';  
17 -  
18 -import './device-alias-select.scss';  
19 -  
20 -/* eslint-disable import/no-unresolved, import/default */  
21 -  
22 -import deviceAliasSelectTemplate from './device-alias-select.tpl.html';  
23 -  
24 -/* eslint-enable import/no-unresolved, import/default */  
25 -  
26 -  
27 -/* eslint-disable angular/angularelement */  
28 -  
29 -export default angular.module('thingsboard.directives.deviceAliasSelect', [])  
30 - .directive('tbDeviceAliasSelect', DeviceAliasSelect)  
31 - .name;  
32 -  
33 -/*@ngInject*/  
34 -function DeviceAliasSelect($compile, $templateCache, $mdConstant) {  
35 -  
36 - var linker = function (scope, element, attrs, ngModelCtrl) {  
37 - var template = $templateCache.get(deviceAliasSelectTemplate);  
38 - element.html(template);  
39 -  
40 - scope.tbRequired = angular.isDefined(scope.tbRequired) ? scope.tbRequired : false;  
41 -  
42 - scope.ngModelCtrl = ngModelCtrl;  
43 - scope.deviceAliasList = [];  
44 - scope.deviceAlias = null;  
45 -  
46 - scope.updateValidity = function () {  
47 - var value = ngModelCtrl.$viewValue;  
48 - var valid = angular.isDefined(value) && value != null || !scope.tbRequired;  
49 - ngModelCtrl.$setValidity('deviceAlias', valid);  
50 - };  
51 -  
52 - scope.$watch('deviceAliases', function () {  
53 - scope.deviceAliasList = [];  
54 - for (var aliasId in scope.deviceAliases) {  
55 - var deviceAlias = {id: aliasId, alias: scope.deviceAliases[aliasId].alias, deviceId: scope.deviceAliases[aliasId].deviceId};  
56 - scope.deviceAliasList.push(deviceAlias);  
57 - }  
58 - }, true);  
59 -  
60 - scope.$watch('deviceAlias', function () {  
61 - scope.updateView();  
62 - });  
63 -  
64 - scope.deviceAliasSearch = function (deviceAliasSearchText) {  
65 - return deviceAliasSearchText ? scope.deviceAliasList.filter(  
66 - scope.createFilterForDeviceAlias(deviceAliasSearchText)) : scope.deviceAliasList;  
67 - };  
68 -  
69 - scope.createFilterForDeviceAlias = function (query) {  
70 - var lowercaseQuery = angular.lowercase(query);  
71 - return function filterFn(deviceAlias) {  
72 - return (angular.lowercase(deviceAlias.alias).indexOf(lowercaseQuery) === 0);  
73 - };  
74 - };  
75 -  
76 - scope.updateView = function () {  
77 - ngModelCtrl.$setViewValue(scope.deviceAlias);  
78 - scope.updateValidity();  
79 - }  
80 -  
81 - ngModelCtrl.$render = function () {  
82 - if (ngModelCtrl.$viewValue) {  
83 - scope.deviceAlias = ngModelCtrl.$viewValue;  
84 - }  
85 - }  
86 -  
87 - scope.textIsNotEmpty = function(text) {  
88 - return (text && text != null && text.length > 0) ? true : false;  
89 - }  
90 -  
91 - scope.deviceAliasEnter = function($event) {  
92 - if ($event.keyCode === $mdConstant.KEY_CODE.ENTER) {  
93 - $event.preventDefault();  
94 - if (!scope.deviceAlias) {  
95 - var found = scope.deviceAliasSearch(scope.deviceAliasSearchText);  
96 - found = found.length > 0;  
97 - if (!found) {  
98 - scope.createDeviceAlias($event, scope.deviceAliasSearchText);  
99 - }  
100 - }  
101 - }  
102 - }  
103 -  
104 - scope.createDeviceAlias = function (event, alias) {  
105 - var autoChild = $('#device-autocomplete', element)[0].firstElementChild;  
106 - var el = angular.element(autoChild);  
107 - el.scope().$mdAutocompleteCtrl.hidden = true;  
108 - el.scope().$mdAutocompleteCtrl.hasNotFound = false;  
109 - event.preventDefault();  
110 - var promise = scope.onCreateDeviceAlias({event: event, alias: alias});  
111 - if (promise) {  
112 - promise.then(  
113 - function success(newAlias) {  
114 - el.scope().$mdAutocompleteCtrl.hasNotFound = true;  
115 - if (newAlias) {  
116 - scope.deviceAliasList.push(newAlias);  
117 - scope.deviceAlias = newAlias;  
118 - }  
119 - },  
120 - function fail() {  
121 - el.scope().$mdAutocompleteCtrl.hasNotFound = true;  
122 - }  
123 - );  
124 - } else {  
125 - el.scope().$mdAutocompleteCtrl.hasNotFound = true;  
126 - }  
127 - };  
128 -  
129 - $compile(element.contents())(scope);  
130 - }  
131 -  
132 - return {  
133 - restrict: "E",  
134 - require: "^ngModel",  
135 - link: linker,  
136 - scope: {  
137 - tbRequired: '=?',  
138 - deviceAliases: '=',  
139 - onCreateDeviceAlias: '&'  
140 - }  
141 - };  
142 -}  
143 -  
144 -/* eslint-enable angular/angularelement */  
1 -<!--  
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 -<section layout='column'>  
19 - <md-autocomplete id="device-autocomplete"  
20 - md-input-name="device_alias"  
21 - ng-required="tbRequired"  
22 - ng-model="deviceAlias"  
23 - md-selected-item="deviceAlias"  
24 - md-search-text="deviceAliasSearchText"  
25 - md-items="item in deviceAliasSearch(deviceAliasSearchText)"  
26 - md-item-text="item.alias"  
27 - tb-keydown="deviceAliasEnter($event)"  
28 - tb-keypress="deviceAliasEnter($event)"  
29 - md-min-length="0"  
30 - placeholder="{{ 'device.device-alias' | translate }}"  
31 - md-menu-class="tb-device-alias-autocomplete">  
32 - <md-item-template>  
33 - <span md-highlight-text="deviceAliasSearchText" md-highlight-flags="^i">{{item.alias}}</span>  
34 - </md-item-template>  
35 - <md-not-found>  
36 - <div class="tb-not-found">  
37 - <div class="tb-no-entries" ng-if="!textIsNotEmpty(deviceAliasSearchText)">  
38 - <span translate>device.no-aliases-found</span>  
39 - </div>  
40 - <div ng-if="textIsNotEmpty(deviceAliasSearchText)">  
41 - <span translate translate-values='{ alias: "{{deviceAliasSearchText | truncate:true:6:&apos;...&apos;}}" }'>device.no-alias-matching</span>  
42 - <span>  
43 - <a translate ng-click="createDeviceAlias($event, deviceAliasSearchText)">device.create-new-alias</a>  
44 - </span>  
45 - </div>  
46 - </div>  
47 - </md-not-found>  
48 - </md-autocomplete>  
49 - <div class="tb-error-messages" ng-messages="ngModelCtrl.$error" role="alert">  
50 - <div translate ng-message="deviceAlias" class="tb-error-message">device.alias-required</div>  
51 - </div>  
52 -</section>  
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 -/* eslint-disable import/no-unresolved, import/default */  
18 -  
19 -import deviceFilterTemplate from './device-filter.tpl.html';  
20 -  
21 -/* eslint-enable import/no-unresolved, import/default */  
22 -  
23 -import './device-filter.scss';  
24 -  
25 -export default angular.module('thingsboard.directives.deviceFilter', [])  
26 - .directive('tbDeviceFilter', DeviceFilter)  
27 - .name;  
28 -  
29 -/*@ngInject*/  
30 -function DeviceFilter($compile, $templateCache, $q, deviceService) {  
31 -  
32 - var linker = function (scope, element, attrs, ngModelCtrl) {  
33 -  
34 - var template = $templateCache.get(deviceFilterTemplate);  
35 - element.html(template);  
36 -  
37 - scope.ngModelCtrl = ngModelCtrl;  
38 -  
39 - scope.fetchDevices = function(searchText, limit) {  
40 - var pageLink = {limit: limit, textSearch: searchText};  
41 -  
42 - var deferred = $q.defer();  
43 -  
44 - deviceService.getTenantDevices(pageLink, false).then(function success(result) {  
45 - deferred.resolve(result.data);  
46 - }, function fail() {  
47 - deferred.reject();  
48 - });  
49 -  
50 - return deferred.promise;  
51 - }  
52 -  
53 - scope.updateValidity = function() {  
54 - if (ngModelCtrl.$viewValue) {  
55 - var value = ngModelCtrl.$viewValue;  
56 - var valid;  
57 - if (value.useFilter) {  
58 - ngModelCtrl.$setValidity('deviceList', true);  
59 - if (angular.isDefined(value.deviceNameFilter) && value.deviceNameFilter.length > 0) {  
60 - ngModelCtrl.$setValidity('deviceNameFilter', true);  
61 - valid = angular.isDefined(scope.model.matchingFilterDevice) && scope.model.matchingFilterDevice != null;  
62 - ngModelCtrl.$setValidity('deviceNameFilterDeviceMatch', valid);  
63 - } else {  
64 - ngModelCtrl.$setValidity('deviceNameFilter', false);  
65 - }  
66 - } else {  
67 - ngModelCtrl.$setValidity('deviceNameFilter', true);  
68 - ngModelCtrl.$setValidity('deviceNameFilterDeviceMatch', true);  
69 - valid = angular.isDefined(value.deviceList) && value.deviceList.length > 0;  
70 - ngModelCtrl.$setValidity('deviceList', valid);  
71 - }  
72 - }  
73 - }  
74 -  
75 - ngModelCtrl.$render = function () {  
76 - destroyWatchers();  
77 - scope.model = {  
78 - useFilter: false,  
79 - deviceList: [],  
80 - deviceNameFilter: ''  
81 - }  
82 - if (ngModelCtrl.$viewValue) {  
83 - var value = ngModelCtrl.$viewValue;  
84 - var model = scope.model;  
85 - model.useFilter = value.useFilter === true ? true: false;  
86 - model.deviceList = [];  
87 - model.deviceNameFilter = value.deviceNameFilter || '';  
88 - processDeviceNameFilter(model.deviceNameFilter).then(  
89 - function(device) {  
90 - scope.model.matchingFilterDevice = device;  
91 - if (value.deviceList && value.deviceList.length > 0) {  
92 - deviceService.getDevices(value.deviceList).then(function (devices) {  
93 - model.deviceList = devices;  
94 - updateMatchingDevice();  
95 - initWatchers();  
96 - });  
97 - } else {  
98 - updateMatchingDevice();  
99 - initWatchers();  
100 - }  
101 - }  
102 - )  
103 - }  
104 - }  
105 -  
106 - function updateMatchingDevice() {  
107 - if (scope.model.useFilter) {  
108 - scope.model.matchingDevice = scope.model.matchingFilterDevice;  
109 - } else {  
110 - if (scope.model.deviceList && scope.model.deviceList.length > 0) {  
111 - scope.model.matchingDevice = scope.model.deviceList[0];  
112 - } else {  
113 - scope.model.matchingDevice = null;  
114 - }  
115 - }  
116 - }  
117 -  
118 - function processDeviceNameFilter(deviceNameFilter) {  
119 - var deferred = $q.defer();  
120 - if (angular.isDefined(deviceNameFilter) && deviceNameFilter.length > 0) {  
121 - scope.fetchDevices(deviceNameFilter, 1).then(function (devices) {  
122 - if (devices && devices.length > 0) {  
123 - deferred.resolve(devices[0]);  
124 - } else {  
125 - deferred.resolve(null);  
126 - }  
127 - });  
128 - } else {  
129 - deferred.resolve(null);  
130 - }  
131 - return deferred.promise;  
132 - }  
133 -  
134 - function destroyWatchers() {  
135 - if (scope.deviceListDeregistration) {  
136 - scope.deviceListDeregistration();  
137 - scope.deviceListDeregistration = null;  
138 - }  
139 - if (scope.useFilterDeregistration) {  
140 - scope.useFilterDeregistration();  
141 - scope.useFilterDeregistration = null;  
142 - }  
143 - if (scope.deviceNameFilterDeregistration) {  
144 - scope.deviceNameFilterDeregistration();  
145 - scope.deviceNameFilterDeregistration = null;  
146 - }  
147 - if (scope.matchingDeviceDeregistration) {  
148 - scope.matchingDeviceDeregistration();  
149 - scope.matchingDeviceDeregistration = null;  
150 - }  
151 - }  
152 -  
153 - function initWatchers() {  
154 - scope.deviceListDeregistration = scope.$watch('model.deviceList', function () {  
155 - if (ngModelCtrl.$viewValue) {  
156 - var value = ngModelCtrl.$viewValue;  
157 - value.deviceList = [];  
158 - if (scope.model.deviceList && scope.model.deviceList.length > 0) {  
159 - for (var i in scope.model.deviceList) {  
160 - value.deviceList.push(scope.model.deviceList[i].id.id);  
161 - }  
162 - }  
163 - updateMatchingDevice();  
164 - ngModelCtrl.$setViewValue(value);  
165 - scope.updateValidity();  
166 - }  
167 - }, true);  
168 - scope.useFilterDeregistration = scope.$watch('model.useFilter', function () {  
169 - if (ngModelCtrl.$viewValue) {  
170 - var value = ngModelCtrl.$viewValue;  
171 - value.useFilter = scope.model.useFilter;  
172 - updateMatchingDevice();  
173 - ngModelCtrl.$setViewValue(value);  
174 - scope.updateValidity();  
175 - }  
176 - });  
177 - scope.deviceNameFilterDeregistration = scope.$watch('model.deviceNameFilter', function (newNameFilter, prevNameFilter) {  
178 - if (ngModelCtrl.$viewValue) {  
179 - if (!angular.equals(newNameFilter, prevNameFilter)) {  
180 - var value = ngModelCtrl.$viewValue;  
181 - value.deviceNameFilter = scope.model.deviceNameFilter;  
182 - processDeviceNameFilter(value.deviceNameFilter).then(  
183 - function(device) {  
184 - scope.model.matchingFilterDevice = device;  
185 - updateMatchingDevice();  
186 - ngModelCtrl.$setViewValue(value);  
187 - scope.updateValidity();  
188 - }  
189 - );  
190 - }  
191 - }  
192 - });  
193 -  
194 - scope.matchingDeviceDeregistration = scope.$watch('model.matchingDevice', function (newMatchingDevice, prevMatchingDevice) {  
195 - if (!angular.equals(newMatchingDevice, prevMatchingDevice)) {  
196 - if (scope.onMatchingDeviceChange) {  
197 - scope.onMatchingDeviceChange({device: newMatchingDevice});  
198 - }  
199 - }  
200 - });  
201 - }  
202 -  
203 - $compile(element.contents())(scope);  
204 -  
205 - }  
206 -  
207 - return {  
208 - restrict: "E",  
209 - require: "^ngModel",  
210 - link: linker,  
211 - scope: {  
212 - isEdit: '=',  
213 - onMatchingDeviceChange: '&'  
214 - }  
215 - };  
216 -  
217 -}  
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 -.tb-device-filter {  
17 - #device_list_chips {  
18 - .md-chips {  
19 - padding-bottom: 1px;  
20 - }  
21 - }  
22 - .device-name-filter-input {  
23 - margin-top: 10px;  
24 - margin-bottom: 0px;  
25 - .md-errors-spacer {  
26 - min-height: 0px;  
27 - }  
28 - }  
29 - .tb-filter-switch {  
30 - padding-left: 10px;  
31 - .filter-switch {  
32 - margin: 0;  
33 - }  
34 - .filter-label {  
35 - margin: 5px 0;  
36 - }  
37 - }  
38 - .tb-error-messages {  
39 - margin-top: -11px;  
40 - height: 35px;  
41 - .tb-error-message {  
42 - padding-left: 1px;  
43 - }  
44 - }  
45 -}  
1 -<!--  
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 -<section layout='column' class="tb-device-filter">  
19 - <section layout='row'>  
20 - <section layout="column" flex ng-show="!model.useFilter">  
21 - <md-chips flex  
22 - id="device_list_chips"  
23 - ng-required="!useFilter"  
24 - ng-model="model.deviceList" md-autocomplete-snap  
25 - md-require-match="true">  
26 - <md-autocomplete  
27 - md-no-cache="true"  
28 - id="device"  
29 - md-selected-item="selectedDevice"  
30 - md-search-text="deviceSearchText"  
31 - md-items="item in fetchDevices(deviceSearchText, 10)"  
32 - md-item-text="item.name"  
33 - md-min-length="0"  
34 - placeholder="{{ 'device.device-list' | translate }}">  
35 - <md-item-template>  
36 - <span md-highlight-text="deviceSearchText" md-highlight-flags="^i">{{item.name}}</span>  
37 - </md-item-template>  
38 - <md-not-found>  
39 - <span translate translate-values='{ device: deviceSearchText }'>device.no-devices-matching</span>  
40 - </md-not-found>  
41 - </md-autocomplete>  
42 - <md-chip-template>  
43 - <span>  
44 - <strong>{{$chip.name}}</strong>  
45 - </span>  
46 - </md-chip-template>  
47 - </md-chips>  
48 - </section>  
49 - <section layout="row" flex ng-show="model.useFilter">  
50 - <md-input-container flex class="device-name-filter-input">  
51 - <label translate>device.name-starts-with</label>  
52 - <input ng-model="model.deviceNameFilter" aria-label="{{ 'device.name-starts-with' | translate }}">  
53 - </md-input-container>  
54 - </section>  
55 - <section class="tb-filter-switch" layout="column" layout-align="center center">  
56 - <label class="tb-small filter-label" translate>device.use-device-name-filter</label>  
57 - <md-switch class="filter-switch" ng-model="model.useFilter" aria-label="use-filter-switcher">  
58 - </md-switch>  
59 - </section>  
60 - </section>  
61 - <div class="tb-error-messages" ng-messages="ngModelCtrl.$error" role="alert">  
62 - <div translate ng-message="deviceList" class="tb-error-message">device.device-list-empty</div>  
63 - <div translate ng-message="deviceNameFilter" class="tb-error-message">device.device-name-filter-required</div>  
64 - <div translate translate-values='{ device: model.deviceNameFilter }' ng-message="deviceNameFilterDeviceMatch"  
65 - class="tb-error-message">device.device-name-filter-no-device-matched</div>  
66 - </div>  
67 -</section>