diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index 4f83c672c3..be35b9aeb2 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -355,10 +355,12 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService pageData = tenantService.findTenants(pageLink); for (Tenant tenant : pageData.getData()) { List deviceTypes = deviceService.findDeviceTypesByTenantId(tenant.getId()).get(); - deviceProfileService.findOrCreateDefaultDeviceProfile(tenant.getId()); + try { + deviceProfileService.createDefaultDeviceProfile(tenant.getId()); + } catch (Exception e){} for (EntitySubtype deviceType : deviceTypes) { try { - deviceProfileService.createDeviceProfile(tenant.getId(), deviceType.getType()); + deviceProfileService.findOrCreateDeviceProfile(tenant.getId(), deviceType.getType()); } catch (Exception e) { } } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java index 8441e7e11d..e38bac68e5 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java @@ -27,6 +27,8 @@ public interface DeviceProfileService { DeviceProfile findDeviceProfileById(TenantId tenantId, DeviceProfileId deviceProfileId); + DeviceProfile findDeviceProfileByName(TenantId tenantId, String profileName); + DeviceProfileInfo findDeviceProfileInfoById(TenantId tenantId, DeviceProfileId deviceProfileId); DeviceProfile saveDeviceProfile(DeviceProfile deviceProfile); @@ -37,12 +39,10 @@ public interface DeviceProfileService { PageData findDeviceProfileInfos(TenantId tenantId, PageLink pageLink); - DeviceProfile findOrCreateDefaultDeviceProfile(TenantId tenantId); + DeviceProfile findOrCreateDeviceProfile(TenantId tenantId, String profileName); DeviceProfile createDefaultDeviceProfile(TenantId tenantId); - DeviceProfile createDeviceProfile(TenantId tenantId, String profileName); - DeviceProfile findDefaultDeviceProfile(TenantId tenantId); DeviceProfileInfo findDefaultDeviceProfileInfo(TenantId tenantId); diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index 05254f612e..019e47f520 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -39,6 +39,7 @@ import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; import lombok.extern.slf4j.Slf4j; import org.springframework.util.StringUtils; +import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.device.profile.MqttTopics; import org.thingsboard.server.common.msg.EncryptionUtil; @@ -574,7 +575,13 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement try { adaptor.convertToPublish(deviceSessionCtx, rpcResponse).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); } catch (Exception e) { - log.trace("[{}] Failed to convert device RPC commandto MQTT msg", sessionId, e); + log.trace("[{}] Failed to convert device RPC command to MQTT msg", sessionId, e); } } + + @Override + public void onProfileUpdate(DeviceProfile deviceProfile) { + deviceSessionCtx.getDeviceInfo().setDeviceType(deviceProfile.getName()); + sessionInfo = SessionInfoProto.newBuilder().mergeFrom(sessionInfo).setDeviceType(deviceProfile.getName()).build(); + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java index bd000f3181..16f849fe73 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java @@ -184,4 +184,15 @@ public interface DeviceDao extends Dao { ListenableFuture findDeviceByTenantIdAndIdAsync(TenantId tenantId, UUID id); Long countDevicesByDeviceProfileId(TenantId tenantId, UUID deviceProfileId); + + /** + * Find devices by tenantId, profileId and page link. + * + * @param tenantId the tenantId + * @param profileId the profileId + * @param pageLink the page link + * @return the list of device objects + */ + PageData findDevicesByTenantIdAndProfileId(UUID tenantId, UUID profileId, PageLink pageLink); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileDao.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileDao.java index 34c12ab90c..267aff358e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileDao.java @@ -37,4 +37,6 @@ public interface DeviceProfileDao extends Dao { DeviceProfile findDefaultDeviceProfile(TenantId tenantId); DeviceProfileInfo findDefaultDeviceProfileInfo(TenantId tenantId); + + DeviceProfile findByName(TenantId tenantId, String profileName); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index 529e1992ac..b40ad102eb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -23,10 +23,12 @@ import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfileInfo; import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceTransportType; +import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration; @@ -44,6 +46,7 @@ import org.thingsboard.server.dao.tenant.TenantDao; import java.util.Arrays; import java.util.Collections; +import java.util.List; import static org.thingsboard.server.common.data.CacheConstants.DEVICE_PROFILE_CACHE; import static org.thingsboard.server.dao.service.Validator.validateId; @@ -54,6 +57,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D private static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; private static final String INCORRECT_DEVICE_PROFILE_ID = "Incorrect deviceProfileId "; + private static final String INCORRECT_DEVICE_PROFILE_NAME = "Incorrect deviceProfileName "; @Autowired private DeviceProfileDao deviceProfileDao; @@ -61,6 +65,9 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @Autowired private DeviceDao deviceDao; + @Autowired + private DeviceService deviceService; + @Autowired private TenantDao tenantDao; @@ -75,6 +82,13 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D return deviceProfileDao.findById(tenantId, deviceProfileId.getId()); } + @Override + public DeviceProfile findDeviceProfileByName(TenantId tenantId, String profileName) { + log.trace("Executing findDeviceProfileByName [{}][{}]", tenantId, profileName); + Validator.validateString(profileName, INCORRECT_DEVICE_PROFILE_NAME + profileName); + return deviceProfileDao.findByName(tenantId, profileName); + } + @Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{'info', #deviceProfileId.id}") @Override public DeviceProfileInfo findDeviceProfileInfoById(TenantId tenantId, DeviceProfileId deviceProfileId) { @@ -87,6 +101,10 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D public DeviceProfile saveDeviceProfile(DeviceProfile deviceProfile) { log.trace("Executing saveDeviceProfile [{}]", deviceProfile); deviceProfileValidator.validate(deviceProfile, DeviceProfile::getTenantId); + DeviceProfile oldDeviceProfile = null; + if (deviceProfile.getId() != null) { + oldDeviceProfile = deviceProfileDao.findById(deviceProfile.getTenantId(), deviceProfile.getId().getId()); + } DeviceProfile savedDeviceProfile; try { savedDeviceProfile = deviceProfileDao.save(deviceProfile.getTenantId(), deviceProfile); @@ -101,10 +119,23 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D Cache cache = cacheManager.getCache(DEVICE_PROFILE_CACHE); cache.evict(Collections.singletonList(savedDeviceProfile.getId().getId())); cache.evict(Arrays.asList("info", savedDeviceProfile.getId().getId())); + cache.evict(Arrays.asList(deviceProfile.getTenantId().getId(), deviceProfile.getName())); if (savedDeviceProfile.isDefault()) { cache.evict(Arrays.asList("default", savedDeviceProfile.getTenantId().getId())); cache.evict(Arrays.asList("default", "info", savedDeviceProfile.getTenantId().getId())); } + if (oldDeviceProfile != null && !oldDeviceProfile.getName().equals(deviceProfile.getName())) { + PageLink pageLink = new PageLink(100); + PageData pageData; + do { + pageData = deviceDao.findDevicesByTenantIdAndProfileId(deviceProfile.getTenantId().getId(), deviceProfile.getUuidId(), pageLink); + for (Device device : pageData.getData()) { + device.setType(deviceProfile.getName()); + deviceService.saveDevice(device); + } + pageLink = pageLink.nextPageLink(); + } while (pageData.hasNext()); + } return savedDeviceProfile; } @@ -116,10 +147,11 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D if (deviceProfile != null && deviceProfile.isDefault()) { throw new DataValidationException("Deletion of Default Device Profile is prohibited!"); } - this.removeDeviceProfile(tenantId, deviceProfileId); + this.removeDeviceProfile(tenantId, deviceProfile); } - private void removeDeviceProfile(TenantId tenantId, DeviceProfileId deviceProfileId) { + private void removeDeviceProfile(TenantId tenantId, DeviceProfile deviceProfile) { + DeviceProfileId deviceProfileId = deviceProfile.getId(); try { deviceProfileDao.removeById(tenantId, deviceProfileId.getId()); } catch (Exception t) { @@ -134,6 +166,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D Cache cache = cacheManager.getCache(DEVICE_PROFILE_CACHE); cache.evict(Collections.singletonList(deviceProfileId.getId())); cache.evict(Arrays.asList("info", deviceProfileId.getId())); + cache.evict(Arrays.asList(tenantId.getId(), deviceProfile.getName())); } @Override @@ -152,12 +185,13 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D return deviceProfileDao.findDeviceProfileInfos(tenantId, pageLink); } + @Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{#tenantId.id, #name}") @Override - public DeviceProfile findOrCreateDefaultDeviceProfile(TenantId tenantId) { + public DeviceProfile findOrCreateDeviceProfile(TenantId tenantId, String name) { log.trace("Executing findOrCreateDefaultDeviceProfile"); - DeviceProfile deviceProfile = findDefaultDeviceProfile(tenantId); + DeviceProfile deviceProfile = findDeviceProfileByName(tenantId, name); if (deviceProfile == null) { - deviceProfile = this.createDefaultDeviceProfile(tenantId); + deviceProfile = this.doCreateDefaultDeviceProfile(tenantId, name, name.equals("default")); } return deviceProfile; } @@ -168,12 +202,6 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D return doCreateDefaultDeviceProfile(tenantId, "default", true); } - @Override - public DeviceProfile createDeviceProfile(TenantId tenantId, String profileName) { - log.trace("Executing createDefaultDeviceProfile tenantId [{}], profileName [{}]", tenantId, profileName); - return doCreateDefaultDeviceProfile(tenantId, profileName, false); - } - private DeviceProfile doCreateDefaultDeviceProfile(TenantId tenantId, String profileName, boolean defaultProfile) { validateId(tenantId, INCORRECT_TENANT_ID + tenantId); DeviceProfile deviceProfile = new DeviceProfile(); @@ -227,6 +255,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D deviceProfileDao.save(tenantId, deviceProfile); cache.evict(Collections.singletonList(previousDefaultDeviceProfile.getId().getId())); cache.evict(Arrays.asList("info", previousDefaultDeviceProfile.getId().getId())); + cache.evict(Arrays.asList(tenantId.getId(), previousDefaultDeviceProfile.getName())); changed = true; } if (changed) { @@ -234,6 +263,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D cache.evict(Arrays.asList("info", deviceProfile.getId().getId())); cache.evict(Arrays.asList("default", tenantId.getId())); cache.evict(Arrays.asList("default", "info", tenantId.getId())); + cache.evict(Arrays.asList(tenantId.getId(), deviceProfile.getName())); } return changed; } @@ -309,7 +339,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @Override protected void removeEntity(TenantId tenantId, DeviceProfile entity) { - removeDeviceProfile(tenantId, entity.getId()); + removeDeviceProfile(tenantId, entity); } }; diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 7153069849..9e52dc8f09 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -169,8 +169,14 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe deviceValidator.validate(device, Device::getTenantId); Device savedDevice; try { + DeviceProfile deviceProfile; if (device.getDeviceProfileId() == null) { - DeviceProfile deviceProfile = this.deviceProfileService.findOrCreateDefaultDeviceProfile(device.getTenantId()); + if (!StringUtils.isEmpty(device.getType())) { + deviceProfile = this.deviceProfileService.findOrCreateDeviceProfile(device.getTenantId(), device.getType()); + } else { + deviceProfile = this.deviceProfileService.findDefaultDeviceProfile(device.getTenantId()); + device.setType(deviceProfile.getName()); + } device.setDeviceProfileId(new DeviceProfileId(deviceProfile.getId().getId())); DeviceData deviceData = new DeviceData(); switch (deviceProfile.getType()) { @@ -178,7 +184,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe deviceData.setConfiguration(new DefaultDeviceConfiguration()); break; } - switch (deviceProfile.getTransportType()){ + switch (deviceProfile.getTransportType()) { case DEFAULT: deviceData.setTransportConfiguration(new DefaultDeviceTransportConfiguration()); break; @@ -190,7 +196,14 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe break; } device.setDeviceData(deviceData); + } else { + deviceProfile = this.deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId()); + if (deviceProfile == null) { + throw new DataValidationException("Device is referencing non existing device profile!"); + } } + device.setType(deviceProfile.getName()); + savedDevice = deviceDao.save(device.getTenantId(), device); } catch (Exception t) { ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); @@ -441,9 +454,6 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @Override protected void validateDataImpl(TenantId tenantId, Device device) { - if (StringUtils.isEmpty(device.getType())) { - throw new DataValidationException("Device type should be specified!"); - } if (StringUtils.isEmpty(device.getName())) { throw new DataValidationException("Device name should be specified!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java index 6c11c328d8..caa8d1da84 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java @@ -20,6 +20,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.query.Param; +import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfileInfo; import org.thingsboard.server.dao.model.sql.DeviceProfileEntity; @@ -53,4 +54,7 @@ public interface DeviceProfileRepository extends PagingAndSortingRepository findByTenantIdAndProfileId(@Param("tenantId") UUID tenantId, + @Param("profileId") UUID profileId, + @Param("searchText") String searchText, + Pageable pageable); + @Query("SELECT new org.thingsboard.server.dao.model.sql.DeviceInfoEntity(d, c.title, c.additionalInfo, p.name) " + "FROM DeviceEntity d " + "LEFT JOIN CustomerEntity c on c.id = d.customerId " + diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java index c68925c177..8c7ee3ae99 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java @@ -104,6 +104,16 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao DaoUtil.toPageable(pageLink))); } + @Override + public PageData findDevicesByTenantIdAndProfileId(UUID tenantId, UUID profileId, PageLink pageLink) { + return DaoUtil.toPageData( + deviceRepository.findByTenantIdAndProfileId( + tenantId, + profileId, + Objects.toString(pageLink.getTextSearch(), ""), + DaoUtil.toPageable(pageLink))); + } + @Override public PageData findDeviceInfosByTenantIdAndCustomerId(UUID tenantId, UUID customerId, PageLink pageLink) { return DaoUtil.toPageData( diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java index 3eb911b054..6f5001a2a2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java @@ -80,4 +80,8 @@ public class JpaDeviceProfileDao extends JpaAbstractSearchTextDao