Browse Source

Merge pull request #9776 from ShvaykaD/feature/profile-names-api

added new get entity profile names APIs for profile entities(AssetProfile & DeviceProfile)
pull/9756/head
Andrew Shvayka 3 years ago
committed by GitHub
parent
commit
acc67a2077
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      application/src/main/java/org/thingsboard/server/controller/AssetController.java
  2. 20
      application/src/main/java/org/thingsboard/server/controller/AssetProfileController.java
  3. 19
      application/src/main/java/org/thingsboard/server/controller/DeviceController.java
  4. 18
      application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java
  5. 4
      application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
  6. 59
      application/src/test/java/org/thingsboard/server/controller/AssetProfileControllerTest.java
  7. 59
      application/src/test/java/org/thingsboard/server/controller/DeviceProfileControllerTest.java
  8. 5
      common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetProfileService.java
  9. 1
      common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetService.java
  10. 5
      common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java
  11. 1
      common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java
  12. 23
      dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java
  13. 3
      dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java
  14. 4
      dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileDao.java
  15. 14
      dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java
  16. 15
      dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java
  17. 1
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java
  18. 4
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileDao.java
  19. 17
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java
  20. 7
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java
  21. 10
      dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetProfileRepository.java
  22. 3
      dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java
  23. 8
      dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java
  24. 8
      dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetProfileDao.java
  25. 11
      dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java
  26. 3
      dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java
  27. 8
      dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java
  28. 8
      dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java
  29. 2
      dao/src/main/resources/sql/schema-entities-idx.sql
  30. 97
      dao/src/test/java/org/thingsboard/server/dao/service/AssetProfileServiceTest.java
  31. 94
      dao/src/test/java/org/thingsboard/server/dao/service/DeviceProfileServiceTest.java
  32. 22
      rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java

4
application/src/main/java/org/thingsboard/server/controller/AssetController.java

@ -397,10 +397,12 @@ public class AssetController extends BaseController {
} }
@ApiOperation(value = "Get Asset Types (getAssetTypes)", @ApiOperation(value = "Get Asset Types (getAssetTypes)",
notes = "Returns a set of unique asset types based on assets that are either owned by the tenant or assigned to the customer which user is performing the request.", produces = MediaType.APPLICATION_JSON_VALUE) notes = "Deprecated. See 'getAssetProfileNames' API from Asset Profile Controller instead." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/asset/types", method = RequestMethod.GET) @RequestMapping(value = "/asset/types", method = RequestMethod.GET)
@ResponseBody @ResponseBody
@Deprecated(since = "3.6.2")
public List<EntitySubtype> getAssetTypes() throws ThingsboardException, ExecutionException, InterruptedException { public List<EntitySubtype> getAssetTypes() throws ThingsboardException, ExecutionException, InterruptedException {
SecurityUser user = getCurrentUser(); SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId(); TenantId tenantId = user.getTenantId();

20
application/src/main/java/org/thingsboard/server/controller/AssetProfileController.java

@ -29,18 +29,23 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.asset.AssetProfile;
import org.thingsboard.server.common.data.asset.AssetProfileInfo; import org.thingsboard.server.common.data.asset.AssetProfileInfo;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AssetProfileId; import org.thingsboard.server.common.data.id.AssetProfileId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.resource.ImageService; import org.thingsboard.server.dao.resource.ImageService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.asset.profile.TbAssetProfileService; import org.thingsboard.server.service.entitiy.asset.profile.TbAssetProfileService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource; import org.thingsboard.server.service.security.permission.Resource;
import java.util.List;
import static org.thingsboard.server.controller.ControllerConstants.ASSET_PROFILE_ID; import static org.thingsboard.server.controller.ControllerConstants.ASSET_PROFILE_ID;
import static org.thingsboard.server.controller.ControllerConstants.ASSET_PROFILE_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ASSET_PROFILE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ASSET_PROFILE_INFO_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ASSET_PROFILE_INFO_DESCRIPTION;
@ -212,4 +217,19 @@ public class AssetProfileController extends BaseController {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(assetProfileService.findAssetProfileInfos(getTenantId(), pageLink)); return checkNotNull(assetProfileService.findAssetProfileInfos(getTenantId(), pageLink));
} }
@ApiOperation(value = "Get Asset Profile names (getAssetProfileNames)",
notes = "Returns a set of unique asset profile names owned by the tenant."
+ TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/assetProfile/names", method = RequestMethod.GET)
@ResponseBody
public List<EntityInfo> getAssetProfileNames(
@ApiParam(value = "Flag indicating whether to retrieve exclusively the names of asset profiles that are referenced by tenant's assets.")
@RequestParam(value = "activeOnly", required = false, defaultValue = "false") boolean activeOnly) throws ThingsboardException {
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
return checkNotNull(assetProfileService.findAssetProfileNamesByTenantId(tenantId, activeOnly));
}
} }

19
application/src/main/java/org/thingsboard/server/controller/DeviceController.java

@ -194,14 +194,14 @@ public class DeviceController extends BaseController {
"Requires to provide the Device Credentials object as well as an existing device profile ID or use \"default\".\n" + "Requires to provide the Device Credentials object as well as an existing device profile ID or use \"default\".\n" +
"You may find the example of device with different type of credentials below: \n\n" + "You may find the example of device with different type of credentials below: \n\n" +
"- Credentials type: <b>\"Access token\"</b> with <b>device profile ID</b> below: \n\n" + "- Credentials type: <b>\"Access token\"</b> with <b>device profile ID</b> below: \n\n" +
DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN + "\n\n" + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN + "\n\n" +
"- Credentials type: <b>\"Access token\"</b> with <b>device profile default</b> below: \n\n" + "- Credentials type: <b>\"Access token\"</b> with <b>device profile default</b> below: \n\n" +
DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DEFAULT_DESCRIPTION_MARKDOWN + "\n\n" + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DEFAULT_DESCRIPTION_MARKDOWN + "\n\n" +
"- Credentials type: <b>\"X509\"</b> with <b>device profile ID</b> below: \n\n" + "- Credentials type: <b>\"X509\"</b> with <b>device profile ID</b> below: \n\n" +
"Note: <b>credentialsId</b> - format <b>Sha3Hash</b>, <b>certificateValue</b> - format <b>PEM</b> (with \"--BEGIN CERTIFICATE----\" and -\"----END CERTIFICATE-\").\n\n" + "Note: <b>credentialsId</b> - format <b>Sha3Hash</b>, <b>certificateValue</b> - format <b>PEM</b> (with \"--BEGIN CERTIFICATE----\" and -\"----END CERTIFICATE-\").\n\n" +
DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_X509_CERTIFICATE_DESCRIPTION_MARKDOWN + "\n\n" + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_X509_CERTIFICATE_DESCRIPTION_MARKDOWN + "\n\n" +
"- Credentials type: <b>\"MQTT_BASIC\"</b> with <b>device profile ID</b> below: \n\n" + "- Credentials type: <b>\"MQTT_BASIC\"</b> with <b>device profile ID</b> below: \n\n" +
DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_MQTT_BASIC_DESCRIPTION_MARKDOWN + "\n\n" + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_MQTT_BASIC_DESCRIPTION_MARKDOWN + "\n\n" +
"- You may find the example of <b>LwM2M</b> device and <b>RPK</b> credentials below: \n\n" + "- You may find the example of <b>LwM2M</b> device and <b>RPK</b> credentials below: \n\n" +
"Note: LwM2M device - only existing device profile ID (Transport configuration -> Transport type: \"LWM2M\".\n\n" + "Note: LwM2M device - only existing device profile ID (Transport configuration -> Transport type: \"LWM2M\".\n\n" +
DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN + "\n\n" + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN + "\n\n" +
@ -304,12 +304,12 @@ public class DeviceController extends BaseController {
"The structure of device credentials id and value is simple for the 'ACCESS_TOKEN' but is much more complex for the 'MQTT_BASIC' or 'LWM2M_CREDENTIALS'.\n" + "The structure of device credentials id and value is simple for the 'ACCESS_TOKEN' but is much more complex for the 'MQTT_BASIC' or 'LWM2M_CREDENTIALS'.\n" +
"You may find the example of device with different type of credentials below: \n\n" + "You may find the example of device with different type of credentials below: \n\n" +
"- Credentials type: <b>\"Access token\"</b> with <b>device ID</b> and with <b>device ID</b> below: \n\n" + "- Credentials type: <b>\"Access token\"</b> with <b>device ID</b> and with <b>device ID</b> below: \n\n" +
DEVICE_UPDATE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN + "\n\n" + DEVICE_UPDATE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN + "\n\n" +
"- Credentials type: <b>\"X509\"</b> with <b>device profile ID</b> below: \n\n" + "- Credentials type: <b>\"X509\"</b> with <b>device profile ID</b> below: \n\n" +
"Note: <b>credentialsId</b> - format <b>Sha3Hash</b>, <b>certificateValue</b> - format <b>PEM</b> (with \"--BEGIN CERTIFICATE----\" and -\"----END CERTIFICATE-\").\n\n" + "Note: <b>credentialsId</b> - format <b>Sha3Hash</b>, <b>certificateValue</b> - format <b>PEM</b> (with \"--BEGIN CERTIFICATE----\" and -\"----END CERTIFICATE-\").\n\n" +
DEVICE_UPDATE_CREDENTIALS_PARAM_X509_CERTIFICATE_DESCRIPTION_MARKDOWN + "\n\n" + DEVICE_UPDATE_CREDENTIALS_PARAM_X509_CERTIFICATE_DESCRIPTION_MARKDOWN + "\n\n" +
"- Credentials type: <b>\"MQTT_BASIC\"</b> with <b>device profile ID</b> below: \n\n" + "- Credentials type: <b>\"MQTT_BASIC\"</b> with <b>device profile ID</b> below: \n\n" +
DEVICE_UPDATE_CREDENTIALS_PARAM_MQTT_BASIC_DESCRIPTION_MARKDOWN + "\n\n" + DEVICE_UPDATE_CREDENTIALS_PARAM_MQTT_BASIC_DESCRIPTION_MARKDOWN + "\n\n" +
"- You may find the example of <b>LwM2M</b> device and <b>RPK</b> credentials below: \n\n" + "- You may find the example of <b>LwM2M</b> device and <b>RPK</b> credentials below: \n\n" +
"Note: LwM2M device - only existing device profile ID (Transport configuration -> Transport type: \"LWM2M\".\n\n" + "Note: LwM2M device - only existing device profile ID (Transport configuration -> Transport type: \"LWM2M\".\n\n" +
DEVICE_UPDATE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN + "\n\n" + DEVICE_UPDATE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN + "\n\n" +
@ -534,11 +534,12 @@ public class DeviceController extends BaseController {
} }
@ApiOperation(value = "Get Device Types (getDeviceTypes)", @ApiOperation(value = "Get Device Types (getDeviceTypes)",
notes = "Returns a set of unique device profile names based on devices that are either owned by the tenant or assigned to the customer which user is performing the request." notes = "Deprecated. See 'getDeviceProfileNames' API from Device Profile Controller instead." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
+ TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/device/types", method = RequestMethod.GET) @RequestMapping(value = "/device/types", method = RequestMethod.GET)
@ResponseBody @ResponseBody
@Deprecated(since = "3.6.2")
public List<EntitySubtype> getDeviceTypes() throws ThingsboardException, ExecutionException, InterruptedException { public List<EntitySubtype> getDeviceTypes() throws ThingsboardException, ExecutionException, InterruptedException {
SecurityUser user = getCurrentUser(); SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId(); TenantId tenantId = user.getTenantId();

18
application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java

@ -32,15 +32,18 @@ import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileInfo; import org.thingsboard.server.common.data.DeviceProfileInfo;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.resource.ImageService; import org.thingsboard.server.dao.resource.ImageService;
import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.dao.timeseries.TimeseriesService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.device.profile.TbDeviceProfileService; import org.thingsboard.server.service.entitiy.device.profile.TbDeviceProfileService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource; import org.thingsboard.server.service.security.permission.Resource;
@ -273,4 +276,19 @@ public class DeviceProfileController extends BaseController {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(deviceProfileService.findDeviceProfileInfos(getTenantId(), pageLink, transportType)); return checkNotNull(deviceProfileService.findDeviceProfileInfos(getTenantId(), pageLink, transportType));
} }
@ApiOperation(value = "Get Device Profile names (getDeviceProfileNames)",
notes = "Returns a set of unique device profile names owned by the tenant."
+ TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/deviceProfile/names", method = RequestMethod.GET)
@ResponseBody
public List<EntityInfo> getDeviceProfileNames(
@ApiParam(value = "Flag indicating whether to retrieve exclusively the names of device profiles that are referenced by tenant's devices.")
@RequestParam(value = "activeOnly", required = false, defaultValue = "false") boolean activeOnly) throws ThingsboardException {
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
return checkNotNull(deviceProfileService.findDeviceProfileNamesByTenantId(tenantId, activeOnly));
}
} }

4
application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java

@ -766,6 +766,10 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
} catch (Exception e) { } catch (Exception e) {
log.warn("Failed to execute update script for save attributes rule nodes due to: ", e); log.warn("Failed to execute update script for save attributes rule nodes due to: ", e);
} }
try {
connection.createStatement().execute("CREATE INDEX IF NOT EXISTS idx_asset_profile_id ON asset(tenant_id, asset_profile_id);");
} catch (Exception e) {
}
}); });
break; break;
default: default:

59
application/src/test/java/org/thingsboard/server/controller/AssetProfileControllerTest.java

@ -28,6 +28,7 @@ import org.springframework.context.annotation.Primary;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
@ -46,11 +47,13 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.thingsboard.server.common.data.DataConstants.DEFAULT_DEVICE_TYPE;
@ContextConfiguration(classes = {AssetProfileControllerTest.Config.class}) @ContextConfiguration(classes = {AssetProfileControllerTest.Config.class})
@DaoSqlTest @DaoSqlTest
@ -459,6 +462,62 @@ public class AssetProfileControllerTest extends AbstractControllerTest {
testEntityDaoWithRelationsTransactionalException(assetProfileDao, savedTenant.getId(), assetProfileId, "/api/assetProfile/" + assetProfileId); testEntityDaoWithRelationsTransactionalException(assetProfileDao, savedTenant.getId(), assetProfileId, "/api/assetProfile/" + assetProfileId);
} }
@Test
public void testGetAssetProfileNames() throws Exception {
var pageLink = new PageLink(Integer.MAX_VALUE);
var assetProfileInfos = doGetTypedWithPageLink("/api/assetProfileInfos?",
new TypeReference<PageData<AssetProfileInfo>>() {
}, pageLink);
Assert.assertNotNull("Asset Profile Infos page data is null!", assetProfileInfos);
Assert.assertEquals("Asset Profile Infos Page data is empty! Expected to have default profile created!", 1, assetProfileInfos.getTotalElements());
List<EntityInfo> expectedAssetProfileNames = assetProfileInfos.getData().stream()
.map(info -> new EntityInfo(info.getId(), info.getName()))
.sorted(Comparator.comparing(EntityInfo::getName))
.collect(Collectors.toList());
var assetProfileNames = doGetTyped("/api/assetProfile/names", new TypeReference<List<EntityInfo>>() {
});
Assert.assertNotNull("Asset Profile Names list is null!", assetProfileNames);
Assert.assertFalse("Asset Profile Names list is empty!", assetProfileNames.isEmpty());
Assert.assertEquals(expectedAssetProfileNames, assetProfileNames);
Assert.assertEquals(1, assetProfileNames.size());
Assert.assertEquals(DEFAULT_DEVICE_TYPE, assetProfileNames.get(0).getName());
int count = 3;
for (int i = 0; i < count; i++) {
Asset asset = new Asset();
asset.setName("AssetName" + i);
asset.setType("AssetProfileName" + i);
Asset savedAsset = doPost("/api/asset", asset, Asset.class);
Assert.assertNotNull(savedAsset);
}
assetProfileInfos = doGetTypedWithPageLink("/api/assetProfileInfos?",
new TypeReference<>() {
}, pageLink);
Assert.assertNotNull("Asset Profile Infos page data is null!", assetProfileInfos);
Assert.assertEquals("Asset Profile Infos Page data is empty! Expected to have default profile created + count value!", 1 + count, assetProfileInfos.getTotalElements());
expectedAssetProfileNames = assetProfileInfos.getData().stream()
.map(info -> new EntityInfo(info.getId(), info.getName()))
.sorted(Comparator.comparing(EntityInfo::getName))
.collect(Collectors.toList());
assetProfileNames = doGetTyped("/api/assetProfile/names", new TypeReference<>() {
});
Assert.assertNotNull("Asset Profile Names list is null!", assetProfileNames);
Assert.assertFalse("Asset Profile Names list is empty!", assetProfileNames.isEmpty());
Assert.assertEquals(expectedAssetProfileNames, assetProfileNames);
Assert.assertEquals(1 + count, assetProfileNames.size());
assetProfileNames = doGetTyped("/api/assetProfile/names?activeOnly=true", new TypeReference<>() {
});
Assert.assertNotNull("Asset Profile Names list is null!", assetProfileNames);
Assert.assertFalse("Asset Profile Names list is empty!", assetProfileNames.isEmpty());
var expectedAssetProfileNamesWithoutDefault = expectedAssetProfileNames.stream()
.filter(entityInfo -> !entityInfo.getName().equals(DEFAULT_DEVICE_TYPE))
.collect(Collectors.toList());
Assert.assertEquals(expectedAssetProfileNamesWithoutDefault, assetProfileNames);
Assert.assertEquals(count, assetProfileNames.size());
}
private AssetProfile savedAssetProfile(String name) { private AssetProfile savedAssetProfile(String name) {
AssetProfile assetProfile = createAssetProfile(name); AssetProfile assetProfile = createAssetProfile(name);
return doPost("/api/assetProfile", assetProfile, AssetProfile.class); return doPost("/api/assetProfile", assetProfile, AssetProfile.class);

59
application/src/test/java/org/thingsboard/server/controller/DeviceProfileControllerTest.java

@ -35,6 +35,7 @@ import org.thingsboard.server.common.data.DeviceProfileInfo;
import org.thingsboard.server.common.data.DeviceProfileProvisionType; import org.thingsboard.server.common.data.DeviceProfileProvisionType;
import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceProfileType;
import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.OtaPackageInfo; import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.SaveOtaPackageInfoRequest; import org.thingsboard.server.common.data.SaveOtaPackageInfoRequest;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
@ -55,11 +56,13 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.thingsboard.server.common.data.DataConstants.DEFAULT_DEVICE_TYPE;
import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE;
import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE; import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE;
@ -1045,6 +1048,62 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
testEntityDaoWithRelationsTransactionalException(deviceProfileDao, savedTenant.getId(), deviceProfileId, "/api/deviceProfile/" + deviceProfileId); testEntityDaoWithRelationsTransactionalException(deviceProfileDao, savedTenant.getId(), deviceProfileId, "/api/deviceProfile/" + deviceProfileId);
} }
@Test
public void testGetDeviceProfileNames() throws Exception {
var pageLink = new PageLink(Integer.MAX_VALUE);
var deviceProfileInfos = doGetTypedWithPageLink("/api/deviceProfileInfos?",
new TypeReference<PageData<DeviceProfileInfo>>() {
}, pageLink);
Assert.assertNotNull("Device Profile Infos page data is null!", deviceProfileInfos);
Assert.assertEquals("Device Profile Infos Page data is empty! Expected to have default profile created!", 1, deviceProfileInfos.getTotalElements());
List<EntityInfo> expectedDeviceProfileNames = deviceProfileInfos.getData().stream()
.map(info -> new EntityInfo(info.getId(), info.getName()))
.sorted(Comparator.comparing(EntityInfo::getName))
.collect(Collectors.toList());
var deviceProfileNames = doGetTyped("/api/deviceProfile/names", new TypeReference<List<EntityInfo>>() {
});
Assert.assertNotNull("Device Profile Names list is null!", deviceProfileNames);
Assert.assertFalse("Device Profile Names list is empty!", deviceProfileNames.isEmpty());
Assert.assertEquals(expectedDeviceProfileNames, deviceProfileNames);
Assert.assertEquals(1, deviceProfileNames.size());
Assert.assertEquals(DEFAULT_DEVICE_TYPE, deviceProfileNames.get(0).getName());
int count = 3;
for (int i = 0; i < count; i++) {
Device device = new Device();
device.setName("DeviceName" + i);
device.setType("DeviceProfileName" + i);
Device savedDevice = doPost("/api/device", device, Device.class);
Assert.assertNotNull(savedDevice);
}
deviceProfileInfos = doGetTypedWithPageLink("/api/deviceProfileInfos?",
new TypeReference<>() {
}, pageLink);
Assert.assertNotNull("Device Profile Infos page data is null!", deviceProfileInfos);
Assert.assertEquals("Device Profile Infos Page data is empty! Expected to have default profile created + count value!", 1 + count, deviceProfileInfos.getTotalElements());
expectedDeviceProfileNames = deviceProfileInfos.getData().stream()
.map(info -> new EntityInfo(info.getId(), info.getName()))
.sorted(Comparator.comparing(EntityInfo::getName))
.collect(Collectors.toList());
deviceProfileNames = doGetTyped("/api/deviceProfile/names", new TypeReference<>() {
});
Assert.assertNotNull("Device Profile Names list is null!", deviceProfileNames);
Assert.assertFalse("Device Profile Names list is empty!", deviceProfileNames.isEmpty());
Assert.assertEquals(expectedDeviceProfileNames, deviceProfileNames);
Assert.assertEquals(1 + count, deviceProfileNames.size());
deviceProfileNames = doGetTyped("/api/deviceProfile/names?activeOnly=true", new TypeReference<>() {
});
Assert.assertNotNull("Device Profile Names list is null!", deviceProfileNames);
Assert.assertFalse("Device Profile Names list is empty!", deviceProfileNames.isEmpty());
var expectedDeviceProfileNamesWithoutDefault = expectedDeviceProfileNames.stream()
.filter(entityInfo -> !entityInfo.getName().equals(DEFAULT_DEVICE_TYPE))
.collect(Collectors.toList());
Assert.assertEquals(expectedDeviceProfileNamesWithoutDefault, deviceProfileNames);
Assert.assertEquals(count, deviceProfileNames.size());
}
private DeviceProfile savedDeviceProfile(String name) { private DeviceProfile savedDeviceProfile(String name) {
DeviceProfile deviceProfile = createDeviceProfile(name); DeviceProfile deviceProfile = createDeviceProfile(name);
return doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); return doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);

5
common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetProfileService.java

@ -15,6 +15,7 @@
*/ */
package org.thingsboard.server.dao.asset; package org.thingsboard.server.dao.asset;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.asset.AssetProfile;
import org.thingsboard.server.common.data.asset.AssetProfileInfo; import org.thingsboard.server.common.data.asset.AssetProfileInfo;
import org.thingsboard.server.common.data.id.AssetProfileId; import org.thingsboard.server.common.data.id.AssetProfileId;
@ -23,6 +24,8 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.entity.EntityDaoService; import org.thingsboard.server.dao.entity.EntityDaoService;
import java.util.List;
public interface AssetProfileService extends EntityDaoService { public interface AssetProfileService extends EntityDaoService {
AssetProfile findAssetProfileById(TenantId tenantId, AssetProfileId assetProfileId); AssetProfile findAssetProfileById(TenantId tenantId, AssetProfileId assetProfileId);
@ -57,4 +60,6 @@ public interface AssetProfileService extends EntityDaoService {
void deleteAssetProfilesByTenantId(TenantId tenantId); void deleteAssetProfilesByTenantId(TenantId tenantId);
List<EntityInfo> findAssetProfileNamesByTenantId(TenantId tenantId, boolean activeOnly);
} }

1
common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetService.java

@ -81,6 +81,7 @@ public interface AssetService extends EntityDaoService {
ListenableFuture<List<Asset>> findAssetsByQuery(TenantId tenantId, AssetSearchQuery query); ListenableFuture<List<Asset>> findAssetsByQuery(TenantId tenantId, AssetSearchQuery query);
@Deprecated(since = "3.6.2", forRemoval = true)
ListenableFuture<List<EntitySubtype>> findAssetTypesByTenantId(TenantId tenantId); ListenableFuture<List<EntitySubtype>> findAssetTypesByTenantId(TenantId tenantId);
Asset assignAssetToEdge(TenantId tenantId, AssetId assetId, EdgeId edgeId); Asset assignAssetToEdge(TenantId tenantId, AssetId assetId, EdgeId edgeId);

5
common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java

@ -17,12 +17,15 @@ package org.thingsboard.server.dao.device;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileInfo; import org.thingsboard.server.common.data.DeviceProfileInfo;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.entity.EntityDaoService; import org.thingsboard.server.dao.entity.EntityDaoService;
import java.util.List;
public interface DeviceProfileService extends EntityDaoService { public interface DeviceProfileService extends EntityDaoService {
DeviceProfile findDeviceProfileById(TenantId tenantId, DeviceProfileId deviceProfileId); DeviceProfile findDeviceProfileById(TenantId tenantId, DeviceProfileId deviceProfileId);
@ -59,4 +62,6 @@ public interface DeviceProfileService extends EntityDaoService {
void deleteDeviceProfilesByTenantId(TenantId tenantId); void deleteDeviceProfilesByTenantId(TenantId tenantId);
List<EntityInfo> findDeviceProfileNamesByTenantId(TenantId tenantId, boolean activeOnly);
} }

1
common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java

@ -95,6 +95,7 @@ public interface DeviceService extends EntityDaoService {
ListenableFuture<List<Device>> findDevicesByQuery(TenantId tenantId, DeviceSearchQuery query); ListenableFuture<List<Device>> findDevicesByQuery(TenantId tenantId, DeviceSearchQuery query);
@Deprecated(since = "3.6.2", forRemoval = true)
ListenableFuture<List<EntitySubtype>> findDeviceTypesByTenantId(TenantId tenantId); ListenableFuture<List<EntitySubtype>> findDeviceTypesByTenantId(TenantId tenantId);
Device assignDeviceToTenant(TenantId tenantId, Device device); Device assignDeviceToTenant(TenantId tenantId, Device device);

23
dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java

@ -19,6 +19,7 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
@ -31,6 +32,7 @@ import org.thingsboard.server.dao.model.ToData;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@ -152,15 +154,26 @@ public abstract class DaoUtil {
} }
} }
public static List<EntitySubtype> convertTenantEntityTypesToDto(UUID tenantId, EntityType entityType, List<String> types) { public static List<EntitySubtype> convertTenantEntityTypesToDto(UUID tenantUUID, EntityType entityType, List<String> types) {
if (CollectionUtils.isEmpty(types)) { if (CollectionUtils.isEmpty(types)) {
return Collections.emptyList(); return Collections.emptyList();
} }
TenantId tenantId = TenantId.fromUUID(tenantUUID);
return types.stream()
.map(type -> new EntitySubtype(tenantId, entityType, type))
.collect(Collectors.toList());
}
List<EntitySubtype> list = new ArrayList<>(types.size()); @Deprecated // used only in deprecated DAO api
for (String type : types) { public static List<EntitySubtype> convertTenantEntityInfosToDto(UUID tenantUUID, EntityType entityType, List<EntityInfo> entityInfos) {
list.add(new EntitySubtype(TenantId.fromUUID(tenantId), entityType, type)); if (CollectionUtils.isEmpty(entityInfos)) {
return Collections.emptyList();
} }
return list; var tenantId = TenantId.fromUUID(tenantUUID);
return entityInfos.stream()
.map(info -> new EntitySubtype(tenantId, entityType, info.getName()))
.sorted(Comparator.comparing(EntitySubtype::getType))
.collect(Collectors.toList());
} }
} }

3
dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java

@ -24,10 +24,8 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.util.TbPair; import org.thingsboard.server.common.data.util.TbPair;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.dao.Dao; import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.ExportableEntityDao; import org.thingsboard.server.dao.ExportableEntityDao;
import org.thingsboard.server.dao.ImageContainerDao;
import org.thingsboard.server.dao.TenantEntityDao; import org.thingsboard.server.dao.TenantEntityDao;
import java.util.List; import java.util.List;
@ -191,6 +189,7 @@ public interface AssetDao extends Dao<Asset>, TenantEntityDao, ExportableEntityD
* *
* @return the list of tenant asset type objects * @return the list of tenant asset type objects
*/ */
@Deprecated(since = "3.6.2", forRemoval = true)
ListenableFuture<List<EntitySubtype>> findTenantAssetTypesAsync(UUID tenantId); ListenableFuture<List<EntitySubtype>> findTenantAssetTypesAsync(UUID tenantId);
Long countAssetsByAssetProfileId(TenantId tenantId, UUID assetProfileId); Long countAssetsByAssetProfileId(TenantId tenantId, UUID assetProfileId);

4
dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileDao.java

@ -15,6 +15,7 @@
*/ */
package org.thingsboard.server.dao.asset; package org.thingsboard.server.dao.asset;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.asset.AssetProfile;
import org.thingsboard.server.common.data.asset.AssetProfileInfo; import org.thingsboard.server.common.data.asset.AssetProfileInfo;
import org.thingsboard.server.common.data.id.AssetProfileId; import org.thingsboard.server.common.data.id.AssetProfileId;
@ -25,6 +26,7 @@ import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.ExportableEntityDao; import org.thingsboard.server.dao.ExportableEntityDao;
import org.thingsboard.server.dao.ImageContainerDao; import org.thingsboard.server.dao.ImageContainerDao;
import java.util.List;
import java.util.UUID; import java.util.UUID;
public interface AssetProfileDao extends Dao<AssetProfile>, ExportableEntityDao<AssetProfileId, AssetProfile>, ImageContainerDao<AssetProfileInfo> { public interface AssetProfileDao extends Dao<AssetProfile>, ExportableEntityDao<AssetProfileId, AssetProfile>, ImageContainerDao<AssetProfileInfo> {
@ -47,4 +49,6 @@ public interface AssetProfileDao extends Dao<AssetProfile>, ExportableEntityDao<
PageData<AssetProfile> findAllWithImages(PageLink pageLink); PageData<AssetProfile> findAllWithImages(PageLink pageLink);
List<EntityInfo> findTenantAssetProfileNames(UUID tenantId, boolean activeOnly);
} }

14
dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java

@ -21,6 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionalEventListener; import org.springframework.transaction.event.TransactionalEventListener;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.Asset;
@ -42,9 +43,11 @@ import org.thingsboard.server.dao.service.PaginatedRemover;
import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.dao.service.Validator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validateId;
@ -318,7 +321,16 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService<AssetPr
return EntityType.ASSET_PROFILE; return EntityType.ASSET_PROFILE;
} }
private PaginatedRemover<TenantId, AssetProfile> tenantAssetProfilesRemover = @Override
public List<EntityInfo> findAssetProfileNamesByTenantId(TenantId tenantId, boolean activeOnly) {
log.trace("Executing findAssetProfileNamesByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
return assetProfileDao.findTenantAssetProfileNames(tenantId.getId(), activeOnly)
.stream().sorted(Comparator.comparing(EntityInfo::getName))
.collect(Collectors.toList());
}
private final PaginatedRemover<TenantId, AssetProfile> tenantAssetProfilesRemover =
new PaginatedRemover<>() { new PaginatedRemover<>() {
@Override @Override

15
dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java

@ -56,7 +56,6 @@ import org.thingsboard.server.dao.service.PaginatedRemover;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -363,7 +362,12 @@ public class BaseAssetService extends AbstractCachedEntityService<AssetCacheKey,
return Futures.successfulAsList(futures); return Futures.successfulAsList(futures);
}, MoreExecutors.directExecutor()); }, MoreExecutors.directExecutor());
assets = Futures.transform(assets, assetList -> assets = Futures.transform(assets, assetList ->
assetList == null ? Collections.emptyList() : assetList.stream().filter(asset -> query.getAssetTypes().contains(asset.getType())).collect(Collectors.toList()), MoreExecutors.directExecutor() assetList == null ?
Collections.emptyList() :
assetList.stream()
.filter(asset -> query.getAssetTypes().contains(asset.getType()))
.collect(Collectors.toList()),
MoreExecutors.directExecutor()
); );
return assets; return assets;
} }
@ -372,12 +376,7 @@ public class BaseAssetService extends AbstractCachedEntityService<AssetCacheKey,
public ListenableFuture<List<EntitySubtype>> findAssetTypesByTenantId(TenantId tenantId) { public ListenableFuture<List<EntitySubtype>> findAssetTypesByTenantId(TenantId tenantId) {
log.trace("Executing findAssetTypesByTenantId, tenantId [{}]", tenantId); log.trace("Executing findAssetTypesByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
ListenableFuture<List<EntitySubtype>> tenantAssetTypes = assetDao.findTenantAssetTypesAsync(tenantId.getId()); return assetDao.findTenantAssetTypesAsync(tenantId.getId());
return Futures.transform(tenantAssetTypes,
assetTypes -> {
assetTypes.sort(Comparator.comparing(EntitySubtype::getType));
return assetTypes;
}, MoreExecutors.directExecutor());
} }
@Override @Override

1
dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java

@ -162,6 +162,7 @@ public interface DeviceDao extends Dao<Device>, TenantEntityDao, ExportableEntit
* *
* @return the list of tenant device type objects * @return the list of tenant device type objects
*/ */
@Deprecated(since = "3.6.2", forRemoval = true)
ListenableFuture<List<EntitySubtype>> findTenantDeviceTypesAsync(UUID tenantId); ListenableFuture<List<EntitySubtype>> findTenantDeviceTypesAsync(UUID tenantId);
/** /**

4
dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileDao.java

@ -17,6 +17,7 @@ package org.thingsboard.server.dao.device;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileInfo; import org.thingsboard.server.common.data.DeviceProfileInfo;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
@ -25,6 +26,7 @@ import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.ExportableEntityDao; import org.thingsboard.server.dao.ExportableEntityDao;
import org.thingsboard.server.dao.ImageContainerDao; import org.thingsboard.server.dao.ImageContainerDao;
import java.util.List;
import java.util.UUID; import java.util.UUID;
public interface DeviceProfileDao extends Dao<DeviceProfile>, ExportableEntityDao<DeviceProfileId, DeviceProfile>, ImageContainerDao<DeviceProfileInfo> { public interface DeviceProfileDao extends Dao<DeviceProfile>, ExportableEntityDao<DeviceProfileId, DeviceProfile>, ImageContainerDao<DeviceProfileInfo> {
@ -49,4 +51,6 @@ public interface DeviceProfileDao extends Dao<DeviceProfile>, ExportableEntityDa
PageData<DeviceProfile> findAllWithImages(PageLink pageLink); PageData<DeviceProfile> findAllWithImages(PageLink pageLink);
List<EntityInfo> findTenantDeviceProfileNames(UUID tenantId, boolean activeOnly);
} }

17
dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java

@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.DeviceProfileInfo;
import org.thingsboard.server.common.data.DeviceProfileProvisionType; import org.thingsboard.server.common.data.DeviceProfileProvisionType;
import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceProfileType;
import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
@ -57,11 +58,13 @@ import java.security.cert.Certificate;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory; import java.security.cert.CertificateFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validateId;
import static org.thingsboard.server.dao.service.Validator.validateString; import static org.thingsboard.server.dao.service.Validator.validateString;
@ -373,7 +376,16 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
return EntityType.DEVICE_PROFILE; return EntityType.DEVICE_PROFILE;
} }
private PaginatedRemover<TenantId, DeviceProfile> tenantDeviceProfilesRemover = @Override
public List<EntityInfo> findDeviceProfileNamesByTenantId(TenantId tenantId, boolean activeOnly) {
log.trace("Executing findDeviceProfileNamesByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
return deviceProfileDao.findTenantDeviceProfileNames(tenantId.getId(), activeOnly)
.stream().sorted(Comparator.comparing(EntityInfo::getName))
.collect(Collectors.toList());
}
private final PaginatedRemover<TenantId, DeviceProfile> tenantDeviceProfilesRemover =
new PaginatedRemover<>() { new PaginatedRemover<>() {
@Override @Override
@ -422,7 +434,8 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
if (certificates.length > 1) { if (certificates.length > 1) {
return EncryptionUtil.certTrimNewLinesForChainInDeviceProfile(certificateValue); return EncryptionUtil.certTrimNewLinesForChainInDeviceProfile(certificateValue);
} }
} catch (CertificateException ignored) {} } catch (CertificateException ignored) {
}
return EncryptionUtil.certTrimNewLines(certificateValue); return EncryptionUtil.certTrimNewLines(certificateValue);
} }

7
dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java

@ -486,12 +486,7 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
public ListenableFuture<List<EntitySubtype>> findDeviceTypesByTenantId(TenantId tenantId) { public ListenableFuture<List<EntitySubtype>> findDeviceTypesByTenantId(TenantId tenantId) {
log.trace("Executing findDeviceTypesByTenantId, tenantId [{}]", tenantId); log.trace("Executing findDeviceTypesByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
ListenableFuture<List<EntitySubtype>> tenantDeviceTypes = deviceDao.findTenantDeviceTypesAsync(tenantId.getId()); return deviceDao.findTenantDeviceTypesAsync(tenantId.getId());
return Futures.transform(tenantDeviceTypes,
deviceTypes -> {
deviceTypes.sort(Comparator.comparing(EntitySubtype::getType));
return deviceTypes;
}, MoreExecutors.directExecutor());
} }
@Transactional @Transactional

10
dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetProfileRepository.java

@ -20,6 +20,7 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.asset.AssetProfileInfo; import org.thingsboard.server.common.data.asset.AssetProfileInfo;
import org.thingsboard.server.dao.ExportableEntityRepository; import org.thingsboard.server.dao.ExportableEntityRepository;
import org.thingsboard.server.dao.model.sql.AssetProfileEntity; import org.thingsboard.server.dao.model.sql.AssetProfileEntity;
@ -71,4 +72,13 @@ public interface AssetProfileRepository extends JpaRepository<AssetProfileEntity
Page<AssetProfileEntity> findAllByImageNotNull(Pageable pageable); Page<AssetProfileEntity> findAllByImageNotNull(Pageable pageable);
@Query("SELECT new org.thingsboard.server.common.data.EntityInfo(ap.id, 'ASSET_PROFILE', ap.name) " +
"FROM AssetProfileEntity ap WHERE ap.tenantId = :tenantId AND EXISTS " +
"(SELECT 1 FROM AssetEntity a WHERE a.tenantId = :tenantId AND a.assetProfileId = ap.id)")
List<EntityInfo> findActiveTenantAssetProfileNames(@Param("tenantId") UUID tenantId);
@Query("SELECT new org.thingsboard.server.common.data.EntityInfo(a.id, 'ASSET_PROFILE', a.name) " +
"FROM AssetProfileEntity a WHERE a.tenantId = :tenantId")
List<EntityInfo> findAllTenantAssetProfileNames(@Param("tenantId") UUID tenantId);
} }

3
dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java

@ -167,9 +167,6 @@ public interface AssetRepository extends JpaRepository<AssetEntity, UUID>, Expor
@Param("textSearch") String textSearch, @Param("textSearch") String textSearch,
Pageable pageable); Pageable pageable);
@Query("SELECT DISTINCT a.type FROM AssetEntity a WHERE a.tenantId = :tenantId")
List<String> findTenantAssetTypes(@Param("tenantId") UUID tenantId);
Long countByAssetProfileId(UUID assetProfileId); Long countByAssetProfileId(UUID assetProfileId);
@Query("SELECT a FROM AssetEntity a, RelationEntity re WHERE a.tenantId = :tenantId " + @Query("SELECT a FROM AssetEntity a, RelationEntity re WHERE a.tenantId = :tenantId " +

8
dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java

@ -39,11 +39,10 @@ import org.thingsboard.server.dao.util.SqlDao;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import static org.thingsboard.server.dao.DaoUtil.convertTenantEntityTypesToDto; import static org.thingsboard.server.dao.DaoUtil.convertTenantEntityInfosToDto;
import static org.thingsboard.server.dao.asset.BaseAssetService.TB_SERVICE_QUEUE; import static org.thingsboard.server.dao.asset.BaseAssetService.TB_SERVICE_QUEUE;
/** /**
@ -57,6 +56,9 @@ public class JpaAssetDao extends JpaAbstractDao<AssetEntity, Asset> implements A
@Autowired @Autowired
private AssetRepository assetRepository; private AssetRepository assetRepository;
@Autowired
private AssetProfileRepository assetProfileRepository;
@Override @Override
protected Class<AssetEntity> getEntityClass() { protected Class<AssetEntity> getEntityClass() {
return AssetEntity.class; return AssetEntity.class;
@ -193,7 +195,7 @@ public class JpaAssetDao extends JpaAbstractDao<AssetEntity, Asset> implements A
@Override @Override
public ListenableFuture<List<EntitySubtype>> findTenantAssetTypesAsync(UUID tenantId) { public ListenableFuture<List<EntitySubtype>> findTenantAssetTypesAsync(UUID tenantId) {
return service.submit(() -> convertTenantEntityTypesToDto(tenantId, EntityType.ASSET, assetRepository.findTenantAssetTypes(tenantId))); return service.submit(() -> convertTenantEntityInfosToDto(tenantId, EntityType.ASSET, assetProfileRepository.findActiveTenantAssetProfileNames(tenantId)));
} }
@Override @Override

8
dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetProfileDao.java

@ -20,6 +20,7 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.asset.AssetProfile;
import org.thingsboard.server.common.data.asset.AssetProfileInfo; import org.thingsboard.server.common.data.asset.AssetProfileInfo;
@ -103,6 +104,13 @@ public class JpaAssetProfileDao extends JpaAbstractDao<AssetProfileEntity, Asset
return DaoUtil.toPageData(assetProfileRepository.findAllByImageNotNull(DaoUtil.toPageable(pageLink))); return DaoUtil.toPageData(assetProfileRepository.findAllByImageNotNull(DaoUtil.toPageable(pageLink)));
} }
@Override
public List<EntityInfo> findTenantAssetProfileNames(UUID tenantId, boolean activeOnly) {
return activeOnly ?
assetProfileRepository.findActiveTenantAssetProfileNames(tenantId) :
assetProfileRepository.findAllTenantAssetProfileNames(tenantId);
}
@Override @Override
public AssetProfile findByTenantIdAndExternalId(UUID tenantId, UUID externalId) { public AssetProfile findByTenantIdAndExternalId(UUID tenantId, UUID externalId) {
return DaoUtil.getData(assetProfileRepository.findByTenantIdAndExternalId(tenantId, externalId)); return DaoUtil.getData(assetProfileRepository.findByTenantIdAndExternalId(tenantId, externalId));

11
dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java

@ -22,7 +22,7 @@ import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
import org.thingsboard.server.common.data.DeviceProfileInfo; import org.thingsboard.server.common.data.DeviceProfileInfo;
import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.asset.AssetProfileInfo; import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.dao.ExportableEntityRepository; import org.thingsboard.server.dao.ExportableEntityRepository;
import org.thingsboard.server.dao.model.sql.DeviceProfileEntity; import org.thingsboard.server.dao.model.sql.DeviceProfileEntity;
@ -83,4 +83,13 @@ public interface DeviceProfileRepository extends JpaRepository<DeviceProfileEnti
Page<DeviceProfileEntity> findAllByImageNotNull(Pageable pageable); Page<DeviceProfileEntity> findAllByImageNotNull(Pageable pageable);
@Query("SELECT new org.thingsboard.server.common.data.EntityInfo(dp.id, 'DEVICE_PROFILE', dp.name) " +
"FROM DeviceProfileEntity dp WHERE dp.tenantId = :tenantId AND EXISTS " +
"(SELECT 1 FROM DeviceEntity dv WHERE dv.tenantId = :tenantId AND dv.deviceProfileId = dp.id)")
List<EntityInfo> findActiveTenantDeviceProfileNames(@Param("tenantId") UUID tenantId);
@Query("SELECT new org.thingsboard.server.common.data.EntityInfo(d.id, 'DEVICE_PROFILE', d.name) " +
"FROM DeviceProfileEntity d WHERE d.tenantId = :tenantId")
List<EntityInfo> findAllTenantDeviceProfileNames(@Param("tenantId") UUID tenantId);
} }

3
dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java

@ -145,9 +145,6 @@ public interface DeviceRepository extends JpaRepository<DeviceEntity, UUID>, Exp
@Param("textSearch") String textSearch, @Param("textSearch") String textSearch,
Pageable pageable); Pageable pageable);
@Query("SELECT DISTINCT d.type FROM DeviceEntity d WHERE d.tenantId = :tenantId")
List<String> findTenantDeviceTypes(@Param("tenantId") UUID tenantId);
DeviceEntity findByTenantIdAndName(UUID tenantId, String name); DeviceEntity findByTenantIdAndName(UUID tenantId, String name);
List<DeviceEntity> findDevicesByTenantIdAndCustomerIdAndIdIn(UUID tenantId, UUID customerId, List<UUID> deviceIds); List<DeviceEntity> findDevicesByTenantIdAndCustomerIdAndIdIn(UUID tenantId, UUID customerId, List<UUID> deviceIds);

8
dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java

@ -44,11 +44,10 @@ import org.thingsboard.server.dao.sql.JpaAbstractDao;
import org.thingsboard.server.dao.util.SqlDao; import org.thingsboard.server.dao.util.SqlDao;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import static org.thingsboard.server.dao.DaoUtil.convertTenantEntityTypesToDto; import static org.thingsboard.server.dao.DaoUtil.convertTenantEntityInfosToDto;
/** /**
* Created by Valerii Sosliuk on 5/6/2017. * Created by Valerii Sosliuk on 5/6/2017.
@ -64,6 +63,9 @@ public class JpaDeviceDao extends JpaAbstractDao<DeviceEntity, Device> implement
@Autowired @Autowired
private NativeDeviceRepository nativeDeviceRepository; private NativeDeviceRepository nativeDeviceRepository;
@Autowired
private DeviceProfileRepository deviceProfileRepository;
@Override @Override
protected Class<DeviceEntity> getEntityClass() { protected Class<DeviceEntity> getEntityClass() {
return DeviceEntity.class; return DeviceEntity.class;
@ -217,7 +219,7 @@ public class JpaDeviceDao extends JpaAbstractDao<DeviceEntity, Device> implement
@Override @Override
public ListenableFuture<List<EntitySubtype>> findTenantDeviceTypesAsync(UUID tenantId) { public ListenableFuture<List<EntitySubtype>> findTenantDeviceTypesAsync(UUID tenantId) {
return service.submit(() -> convertTenantEntityTypesToDto(tenantId, EntityType.DEVICE, deviceRepository.findTenantDeviceTypes(tenantId))); return service.submit(() -> convertTenantEntityInfosToDto(tenantId, EntityType.DEVICE, deviceProfileRepository.findActiveTenantDeviceProfileNames(tenantId)));
} }
@Override @Override

8
dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java

@ -23,6 +23,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileInfo; import org.thingsboard.server.common.data.DeviceProfileInfo;
import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.DeviceProfileId;
@ -121,6 +122,13 @@ public class JpaDeviceProfileDao extends JpaAbstractDao<DeviceProfileEntity, Dev
return DaoUtil.toPageData(deviceProfileRepository.findAllByImageNotNull(DaoUtil.toPageable(pageLink))); return DaoUtil.toPageData(deviceProfileRepository.findAllByImageNotNull(DaoUtil.toPageable(pageLink)));
} }
@Override
public List<EntityInfo> findTenantDeviceProfileNames(UUID tenantId, boolean activeOnly) {
return activeOnly ?
deviceProfileRepository.findActiveTenantDeviceProfileNames(tenantId) :
deviceProfileRepository.findAllTenantDeviceProfileNames(tenantId);
}
@Override @Override
public DeviceProfile findByTenantIdAndExternalId(UUID tenantId, UUID externalId) { public DeviceProfile findByTenantIdAndExternalId(UUID tenantId, UUID externalId) {
return DaoUtil.getData(deviceProfileRepository.findByTenantIdAndExternalId(tenantId, externalId)); return DaoUtil.getData(deviceProfileRepository.findByTenantIdAndExternalId(tenantId, externalId));

2
dao/src/main/resources/sql/schema-entities-idx.sql

@ -57,6 +57,8 @@ CREATE INDEX IF NOT EXISTS idx_asset_customer_id_and_type ON asset(tenant_id, cu
CREATE INDEX IF NOT EXISTS idx_asset_type ON asset(tenant_id, type); CREATE INDEX IF NOT EXISTS idx_asset_type ON asset(tenant_id, type);
CREATE INDEX IF NOT EXISTS idx_asset_profile_id ON asset(tenant_id, asset_profile_id);
CREATE INDEX IF NOT EXISTS idx_attribute_kv_by_key_and_last_update_ts ON attribute_kv(entity_id, attribute_key, last_update_ts desc); CREATE INDEX IF NOT EXISTS idx_attribute_kv_by_key_and_last_update_ts ON attribute_kv(entity_id, attribute_key, last_update_ts desc);
CREATE INDEX IF NOT EXISTS idx_audit_log_tenant_id_and_created_time ON audit_log(tenant_id, created_time DESC); CREATE INDEX IF NOT EXISTS idx_audit_log_tenant_id_and_created_time ON audit_log(tenant_id, created_time DESC);

97
dao/src/test/java/org/thingsboard/server/dao/service/AssetProfileServiceTest.java

@ -24,6 +24,7 @@ import org.junit.Test;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.asset.AssetProfile;
import org.thingsboard.server.common.data.asset.AssetProfileInfo; import org.thingsboard.server.common.data.asset.AssetProfileInfo;
@ -35,11 +36,14 @@ import org.thingsboard.server.dao.exception.DataValidationException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
@DaoSqlTest @DaoSqlTest
public class AssetProfileServiceTest extends AbstractServiceTest { public class AssetProfileServiceTest extends AbstractServiceTest {
@ -272,4 +276,97 @@ public class AssetProfileServiceTest extends AbstractServiceTest {
Assert.assertEquals(1, pageData.getTotalElements()); Assert.assertEquals(1, pageData.getTotalElements());
} }
@Test
public void testFindAllassetProfilesByTenantId() {
int assetProfilesCount = 4; // 3 created + default
var assetProfiles = new ArrayList<AssetProfile>(4);
var profileC = assetProfileService.saveAssetProfile(
createAssetProfile(tenantId, "profile C"));
assetProfiles.add(assetProfileService.saveAssetProfile(profileC));
var profileA = assetProfileService.saveAssetProfile(
createAssetProfile(tenantId, "profile A"));
assetProfiles.add(assetProfileService.saveAssetProfile(profileA));
var profileB = assetProfileService.saveAssetProfile(
createAssetProfile(tenantId, "profile B"));
assetProfiles.add(assetProfileService.saveAssetProfile(profileB));
assetProfiles.add(assetProfileService.findDefaultAssetProfile(tenantId));
List<EntityInfo> sortedProfileInfos = assetProfiles.stream()
.map(profile -> new EntityInfo(profile.getId(), profile.getName()))
.sorted(Comparator.comparing(EntityInfo::getName))
.collect(Collectors.toList());
var assetProfileInfos = assetProfileService
.findAssetProfileNamesByTenantId(tenantId, false);
assertThat(assetProfileInfos).isNotNull();
assertThat(assetProfileInfos).hasSize(assetProfilesCount);
assertThat(assetProfileInfos).isEqualTo(sortedProfileInfos);
}
@Test
public void testFindActiveOnlyassetProfilesByTenantId() {
String profileCName = "profile C";
assetProfileService.saveAssetProfile(
createAssetProfile(tenantId, profileCName));
String profileAName = "profile A";
assetProfileService.saveAssetProfile(
createAssetProfile(tenantId, profileAName));
String profileBName = "profile B";
assetProfileService.saveAssetProfile(
createAssetProfile(tenantId, profileBName));
var assetProfileInfos = assetProfileService
.findAssetProfileNamesByTenantId(tenantId, true);
assertThat(assetProfileInfos).isNotNull();
assertThat(assetProfileInfos).isEmpty();
var assetC = new Asset();
assetC.setName("Test asset C");
assetC.setType(profileCName);
assetC.setTenantId(tenantId);
assetC = assetService.saveAsset(assetC);
var assetA = new Asset();
assetA.setName("Test asset A");
assetA.setType(profileAName);
assetA.setTenantId(tenantId);
assetA = assetService.saveAsset(assetA);
var assetB = new Asset();
assetB.setName("Test asset B");
assetB.setType(profileBName);
assetB.setTenantId(tenantId);
assetB = assetService.saveAsset(assetB);
assetProfileInfos = assetProfileService
.findAssetProfileNamesByTenantId(tenantId, true);
var expected = List.of(
new EntityInfo(assetA.getAssetProfileId(), profileAName),
new EntityInfo(assetB.getAssetProfileId(), profileBName),
new EntityInfo(assetC.getAssetProfileId(), profileCName)
);
assertThat(assetProfileInfos).isNotEmpty();
assertThat(assetProfileInfos).hasSize(3);
assertThat(assetProfileInfos).isEqualTo(expected);
}
} }

94
dao/src/test/java/org/thingsboard/server/dao/service/DeviceProfileServiceTest.java

@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileInfo; import org.thingsboard.server.common.data.DeviceProfileInfo;
import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.OtaPackage; import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
@ -41,6 +42,7 @@ import org.thingsboard.server.dao.ota.OtaPackageService;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -372,4 +374,96 @@ public class DeviceProfileServiceTest extends AbstractServiceTest {
Assert.assertEquals(1, pageData.getTotalElements()); Assert.assertEquals(1, pageData.getTotalElements());
} }
@Test
public void testFindAllDeviceProfilesByTenantId() {
int deviceProfilesCount = 4; // 3 created + default
var deviceProfiles = new ArrayList<DeviceProfile>(4);
var profileC = deviceProfileService.saveDeviceProfile(
createDeviceProfile(tenantId, "profile C"));
deviceProfiles.add(deviceProfileService.saveDeviceProfile(profileC));
var profileA = deviceProfileService.saveDeviceProfile(
createDeviceProfile(tenantId, "profile A"));
deviceProfiles.add(deviceProfileService.saveDeviceProfile(profileA));
var profileB = deviceProfileService.saveDeviceProfile(
createDeviceProfile(tenantId, "profile B"));
deviceProfiles.add(deviceProfileService.saveDeviceProfile(profileB));
deviceProfiles.add(deviceProfileService.findDefaultDeviceProfile(tenantId));
List<EntityInfo> sortedProfileInfos = deviceProfiles.stream()
.map(profile -> new EntityInfo(profile.getId(), profile.getName()))
.sorted(Comparator.comparing(EntityInfo::getName))
.collect(Collectors.toList());
var deviceProfileInfos = deviceProfileService
.findDeviceProfileNamesByTenantId(tenantId, false);
assertThat(deviceProfileInfos).isNotNull();
assertThat(deviceProfileInfos).hasSize(deviceProfilesCount);
assertThat(deviceProfileInfos).isEqualTo(sortedProfileInfos);
}
@Test
public void testFindActiveOnlyDeviceProfilesByTenantId() {
String profileCName = "profile C";
deviceProfileService.saveDeviceProfile(
createDeviceProfile(tenantId, profileCName));
String profileAName = "profile A";
deviceProfileService.saveDeviceProfile(
createDeviceProfile(tenantId, profileAName));
String profileBName = "profile B";
deviceProfileService.saveDeviceProfile(
createDeviceProfile(tenantId, profileBName));
var deviceProfileInfos = deviceProfileService
.findDeviceProfileNamesByTenantId(tenantId, true);
assertThat(deviceProfileInfos).isNotNull();
assertThat(deviceProfileInfos).isEmpty();
var deviceC = new Device();
deviceC.setName("Test Device C");
deviceC.setType(profileCName);
deviceC.setTenantId(tenantId);
deviceC = deviceService.saveDevice(deviceC);
var deviceA = new Device();
deviceA.setName("Test Device A");
deviceA.setType(profileAName);
deviceA.setTenantId(tenantId);
deviceA = deviceService.saveDevice(deviceA);
var deviceB = new Device();
deviceB.setName("Test Device B");
deviceB.setType(profileBName);
deviceB.setTenantId(tenantId);
deviceB = deviceService.saveDevice(deviceB);
deviceProfileInfos = deviceProfileService
.findDeviceProfileNamesByTenantId(tenantId, true);
var expected = List.of(
new EntityInfo(deviceA.getDeviceProfileId(), profileAName),
new EntityInfo(deviceB.getDeviceProfileId(), profileBName),
new EntityInfo(deviceC.getDeviceProfileId(), profileCName)
);
assertThat(deviceProfileInfos).isNotEmpty();
assertThat(deviceProfileInfos).hasSize(3);
assertThat(deviceProfileInfos).isEqualTo(expected);
}
} }

22
rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java

@ -505,7 +505,7 @@ public class RestClient implements Closeable {
HttpMethod.GET, HttpMethod.GET,
HttpEntity.EMPTY, HttpEntity.EMPTY,
new ParameterizedTypeReference<List<EntitySubtype>>() { new ParameterizedTypeReference<List<EntitySubtype>>() {
}).getBody(); }).getBody();
} }
public AlarmComment saveAlarmComment(AlarmId alarmId, AlarmComment alarmComment) { public AlarmComment saveAlarmComment(AlarmId alarmId, AlarmComment alarmComment) {
@ -703,6 +703,7 @@ public class RestClient implements Closeable {
}).getBody(); }).getBody();
} }
@Deprecated(since = "3.6.2")
public List<EntitySubtype> getAssetTypes() { public List<EntitySubtype> getAssetTypes() {
return restTemplate.exchange(URI.create( return restTemplate.exchange(URI.create(
baseURL + "/api/asset/types"), baseURL + "/api/asset/types"),
@ -712,6 +713,15 @@ public class RestClient implements Closeable {
}).getBody(); }).getBody();
} }
public List<EntitySubtype> getAssetProfileNames(boolean activeOnly) {
return restTemplate.exchange(
baseURL + "/api/assetProfile/names?activeOnly={activeOnly}",
HttpMethod.GET,
HttpEntity.EMPTY,
new ParameterizedTypeReference<List<EntitySubtype>>() {
}, activeOnly).getBody();
}
public BulkImportResult<Asset> processAssetsBulkImport(BulkImportRequest request) { public BulkImportResult<Asset> processAssetsBulkImport(BulkImportRequest request) {
return restTemplate.exchange( return restTemplate.exchange(
baseURL + "/api/asset/bulk_import", baseURL + "/api/asset/bulk_import",
@ -1394,6 +1404,7 @@ public class RestClient implements Closeable {
}).getBody(); }).getBody();
} }
@Deprecated(since = "3.6.2")
public List<EntitySubtype> getDeviceTypes() { public List<EntitySubtype> getDeviceTypes() {
return restTemplate.exchange( return restTemplate.exchange(
baseURL + "/api/device/types", baseURL + "/api/device/types",
@ -1403,6 +1414,15 @@ public class RestClient implements Closeable {
}).getBody(); }).getBody();
} }
public List<EntitySubtype> getDeviceProfileNames(boolean activeOnly) {
return restTemplate.exchange(
baseURL + "/api/deviceProfile/names?activeOnly={activeOnly}",
HttpMethod.GET,
HttpEntity.EMPTY,
new ParameterizedTypeReference<List<EntitySubtype>>() {
}, activeOnly).getBody();
}
public JsonNode claimDevice(String deviceName, ClaimRequest claimRequest) { public JsonNode claimDevice(String deviceName, ClaimRequest claimRequest) {
return restTemplate.exchange( return restTemplate.exchange(
baseURL + "/api/customer/device/{deviceName}/claim", baseURL + "/api/customer/device/{deviceName}/claim",

Loading…
Cancel
Save