@ -17,17 +17,23 @@ package org.thingsboard.server.dao.device;
import lombok.extern.slf4j.Slf4j ;
import lombok.extern.slf4j.Slf4j ;
import org.hibernate.exception.ConstraintViolationException ;
import org.hibernate.exception.ConstraintViolationException ;
import org.jetbrains.annotations.Nullable ;
import org.springframework.beans.factory.annotation.Autowired ;
import org.springframework.beans.factory.annotation.Autowired ;
import org.springframework.cache.Cache ;
import org.springframework.cache.Cache ;
import org.springframework.cache.CacheManager ;
import org.springframework.cache.CacheManager ;
import org.springframework.cache.annotation.Cacheable ;
import org.springframework.cache.annotation.Cacheable ;
import org.springframework.stereotype.Service ;
import org.springframework.stereotype.Service ;
import org.springframework.transaction.annotation.Propagation ;
import org.springframework.transaction.annotation.Transactional ;
import org.springframework.transaction.event.TransactionalEventListener ;
import org.thingsboard.server.common.data.Device ;
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.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.StringUtils ;
import org.thingsboard.server.common.data.TenantProfile ;
import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration ;
import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration ;
import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration ;
import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration ;
import org.thingsboard.server.common.data.device.profile.DeviceProfileData ;
import org.thingsboard.server.common.data.device.profile.DeviceProfileData ;
@ -36,14 +42,20 @@ 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.asset.AssetCacheKey ;
import org.thingsboard.server.dao.entity.AbstractCachedEntityService ;
import org.thingsboard.server.dao.entity.AbstractEntityService ;
import org.thingsboard.server.dao.entity.AbstractEntityService ;
import org.thingsboard.server.dao.exception.DataValidationException ;
import org.thingsboard.server.dao.exception.DataValidationException ;
import org.thingsboard.server.dao.service.DataValidator ;
import org.thingsboard.server.dao.service.DataValidator ;
import org.thingsboard.server.dao.service.PaginatedRemover ;
import org.thingsboard.server.dao.service.PaginatedRemover ;
import org.thingsboard.server.dao.service.Validator ;
import org.thingsboard.server.dao.service.Validator ;
import org.thingsboard.server.dao.tenant.TenantProfileCacheKey ;
import org.thingsboard.server.dao.tenant.TenantProfileEvictEvent ;
import java.util.ArrayList ;
import java.util.Arrays ;
import java.util.Arrays ;
import java.util.Collections ;
import java.util.Collections ;
import java.util.List ;
import java.util.concurrent.locks.Lock ;
import java.util.concurrent.locks.Lock ;
import java.util.concurrent.locks.ReentrantLock ;
import java.util.concurrent.locks.ReentrantLock ;
@ -52,7 +64,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId;
@Service
@Service
@Slf4j
@Slf4j
public class DeviceProfileServiceImpl extends AbstractEntityService implements DeviceProfileService {
public class DeviceProfileServiceImpl extends AbstractCached EntityService < DeviceProfileCacheKey , DeviceProfile , DeviceProfileEvictEvent > implements DeviceProfileService {
private static final String INCORRECT_TENANT_ID = "Incorrect tenantId " ;
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_ID = "Incorrect deviceProfileId " ;
@ -67,51 +79,60 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
@Autowired
@Autowired
private DeviceService deviceService ;
private DeviceService deviceService ;
@Autowired
private CacheManager cacheManager ;
@Autowired
@Autowired
private DataValidator < DeviceProfile > deviceProfileValidator ;
private DataValidator < DeviceProfile > deviceProfileValidator ;
private final Lock findOrCreateLock = new ReentrantLock ( ) ;
private final Lock findOrCreateLock = new ReentrantLock ( ) ;
@Cacheable ( cacheNames = DEVICE_PROFILE_CACHE , key = "{#deviceProfileId.id}" )
@TransactionalEventListener ( classes = DeviceProfileEvictEvent . class )
@Override
public void handleEvictEvent ( DeviceProfileEvictEvent event ) {
List < DeviceProfileCacheKey > keys = new ArrayList < > ( 2 ) ;
keys . add ( DeviceProfileCacheKey . fromId ( event . getDeviceProfileId ( ) ) ) ;
keys . add ( DeviceProfileCacheKey . fromName ( event . getTenantId ( ) , event . getNewName ( ) ) ) ;
if ( event . isDefaultProfile ( ) ) {
keys . add ( DeviceProfileCacheKey . defaultProfile ( event . getTenantId ( ) ) ) ;
}
if ( StringUtils . isNotEmpty ( event . getOldName ( ) ) & & ! event . getOldName ( ) . equals ( event . getNewName ( ) ) ) {
keys . add ( DeviceProfileCacheKey . fromName ( event . getTenantId ( ) , event . getOldName ( ) ) ) ;
}
cache . evict ( keys ) ;
}
@Override
@Override
public DeviceProfile findDeviceProfileById ( TenantId tenantId , DeviceProfileId deviceProfileId ) {
public DeviceProfile findDeviceProfileById ( TenantId tenantId , DeviceProfileId deviceProfileId ) {
log . trace ( "Executing findDeviceProfileById [{}]" , deviceProfileId ) ;
log . trace ( "Executing findDeviceProfileById [{}]" , deviceProfileId ) ;
Validator . validateId ( deviceProfileId , INCORRECT_DEVICE_PROFILE_ID + deviceProfileId ) ;
Validator . validateId ( deviceProfileId , INCORRECT_DEVICE_PROFILE_ID + deviceProfileId ) ;
return deviceProfileDao . findById ( tenantId , deviceProfileId . getId ( ) ) ;
return cache . getAndPutInTransaction ( DeviceProfileCacheKey . fromId ( deviceProfileId ) ,
( ) - > deviceProfileDao . findById ( tenantId , deviceProfileId . getId ( ) ) , true ) ;
}
}
@Override
@Override
public DeviceProfile findDeviceProfileByName ( TenantId tenantId , String profileName ) {
public DeviceProfile findDeviceProfileByName ( TenantId tenantId , String profileName ) {
log . trace ( "Executing findDeviceProfileByName [{}][{}]" , tenantId , profileName ) ;
log . trace ( "Executing findDeviceProfileByName [{}][{}]" , tenantId , profileName ) ;
Validator . validateString ( profileName , INCORRECT_DEVICE_PROFILE_NAME + profileName ) ;
Validator . validateString ( profileName , INCORRECT_DEVICE_PROFILE_NAME + profileName ) ;
return deviceProfileDao . findByName ( tenantId , profileName ) ;
return cache . getAndPutInTransaction ( DeviceProfileCacheKey . fromName ( tenantId , profileName ) ,
( ) - > deviceProfileDao . findByName ( tenantId , profileName ) , true ) ;
}
}
@Cacheable ( cacheNames = DEVICE_PROFILE_CACHE , key = "{'info', #deviceProfileId.id}" )
@Override
@Override
public DeviceProfileInfo findDeviceProfileInfoById ( TenantId tenantId , DeviceProfileId deviceProfileId ) {
public DeviceProfileInfo findDeviceProfileInfoById ( TenantId tenantId , DeviceProfileId deviceProfileId ) {
log . trace ( "Executing findDeviceProfileById [{}]" , deviceProfileId ) ;
log . trace ( "Executing findDeviceProfileById [{}]" , deviceProfileId ) ;
Validator . validateId ( deviceProfileId , INCORRECT_DEVICE_PROFILE_ID + deviceProfileId ) ;
Validator . validateId ( deviceProfileId , INCORRECT_DEVICE_PROFILE_ID + deviceProfileId ) ;
return deviceProfileDao . findDeviceProfileInfo ById( tenantId , deviceProfileId . getId ( ) ) ;
return toDeviceProfileInfo ( findDeviceProfile ById( tenantId , deviceProfileId ) ) ;
}
}
@Override
@Override
public DeviceProfile saveDeviceProfile ( DeviceProfile deviceProfile ) {
public DeviceProfile saveDeviceProfile ( DeviceProfile deviceProfile ) {
log . trace ( "Executing saveDeviceProfile [{}]" , deviceProfile ) ;
log . trace ( "Executing saveDeviceProfile [{}]" , deviceProfile ) ;
deviceProfileValidator . validate ( deviceProfile , DeviceProfile : : getTenantId ) ;
DeviceProfile oldDeviceProfile = deviceProfileValidator . validate ( deviceProfile , DeviceProfile : : getTenantId ) ;
DeviceProfile oldDeviceProfile = null ;
if ( deviceProfile . getId ( ) ! = null ) {
oldDeviceProfile = deviceProfileDao . findById ( deviceProfile . getTenantId ( ) , deviceProfile . getId ( ) . getId ( ) ) ;
}
DeviceProfile savedDeviceProfile ;
DeviceProfile savedDeviceProfile ;
try {
try {
savedDeviceProfile = deviceProfileDao . saveAndFlush ( deviceProfile . getTenantId ( ) , deviceProfile ) ;
savedDeviceProfile = deviceProfileDao . saveAndFlush ( deviceProfile . getTenantId ( ) , deviceProfile ) ;
} catch ( Exception t ) {
} catch ( Exception t ) {
ConstraintViolationException e = extractConstraintViolationException ( t ) . orElse ( null ) ;
ConstraintViolationException e = extractConstraintViolationException ( t ) . orElse ( null ) ;
if ( e ! = null & & e . getConstraintName ( ) ! = null & & e . getConstraintName ( ) . equalsIgnoreCase ( "device_profile_name_unq_key" ) ) {
if ( e ! = null & & e . getConstraintName ( ) ! = null & & e . getConstraintName ( ) . equalsIgnoreCase ( "device_profile_name_unq_key" ) ) {
//TODO: refactor this to return existing device profile. If they are equal - no need to throw exception. Then we can make this call @Transactional and tests will not fail.
throw new DataValidationException ( "Device profile with such name already exists!" ) ;
throw new DataValidationException ( "Device profile with such name already exists!" ) ;
} else if ( e ! = null & & e . getConstraintName ( ) ! = null & & e . getConstraintName ( ) . equalsIgnoreCase ( "device_provision_key_unq_key" ) ) {
} else if ( e ! = null & & e . getConstraintName ( ) ! = null & & e . getConstraintName ( ) . equalsIgnoreCase ( "device_provision_key_unq_key" ) ) {
throw new DataValidationException ( "Device profile with such provision device key already exists!" ) ;
throw new DataValidationException ( "Device profile with such provision device key already exists!" ) ;
@ -119,14 +140,8 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
throw t ;
throw t ;
}
}
}
}
Cache cache = cacheManager . getCache ( DEVICE_PROFILE_CACHE ) ;
publishEvictEvent ( new DeviceProfileEvictEvent ( savedDeviceProfile . getTenantId ( ) , savedDeviceProfile . getName ( ) ,
cache . evict ( Collections . singletonList ( savedDeviceProfile . getId ( ) . getId ( ) ) ) ;
oldDeviceProfile ! = null ? oldDeviceProfile . getName ( ) : null , savedDeviceProfile . getId ( ) , savedDeviceProfile . isDefault ( ) ) ) ;
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 ( ) ) ) {
if ( oldDeviceProfile ! = null & & ! oldDeviceProfile . getName ( ) . equals ( deviceProfile . getName ( ) ) ) {
PageLink pageLink = new PageLink ( 100 ) ;
PageLink pageLink = new PageLink ( 100 ) ;
PageData < Device > pageData ;
PageData < Device > pageData ;
@ -142,6 +157,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
return savedDeviceProfile ;
return savedDeviceProfile ;
}
}
@Transactional ( propagation = Propagation . SUPPORTS )
@Override
@Override
public void deleteDeviceProfile ( TenantId tenantId , DeviceProfileId deviceProfileId ) {
public void deleteDeviceProfile ( TenantId tenantId , DeviceProfileId deviceProfileId ) {
log . trace ( "Executing deleteDeviceProfile [{}]" , deviceProfileId ) ;
log . trace ( "Executing deleteDeviceProfile [{}]" , deviceProfileId ) ;
@ -157,6 +173,8 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
DeviceProfileId deviceProfileId = deviceProfile . getId ( ) ;
DeviceProfileId deviceProfileId = deviceProfile . getId ( ) ;
try {
try {
deviceProfileDao . removeById ( tenantId , deviceProfileId . getId ( ) ) ;
deviceProfileDao . removeById ( tenantId , deviceProfileId . getId ( ) ) ;
publishEvictEvent ( new DeviceProfileEvictEvent ( deviceProfile . getTenantId ( ) , deviceProfile . getName ( ) ,
null , deviceProfile . getId ( ) , deviceProfile . isDefault ( ) ) ) ;
} catch ( Exception t ) {
} catch ( Exception t ) {
ConstraintViolationException e = extractConstraintViolationException ( t ) . orElse ( null ) ;
ConstraintViolationException e = extractConstraintViolationException ( t ) . orElse ( null ) ;
if ( e ! = null & & e . getConstraintName ( ) ! = null & & e . getConstraintName ( ) . equalsIgnoreCase ( "fk_device_profile" ) ) {
if ( e ! = null & & e . getConstraintName ( ) ! = null & & e . getConstraintName ( ) . equalsIgnoreCase ( "fk_device_profile" ) ) {
@ -166,10 +184,6 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
}
}
}
}
deleteEntityRelations ( tenantId , deviceProfileId ) ;
deleteEntityRelations ( tenantId , deviceProfileId ) ;
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
@Override
@ -188,7 +202,6 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
return deviceProfileDao . findDeviceProfileInfos ( tenantId , pageLink , transportType ) ;
return deviceProfileDao . findDeviceProfileInfos ( tenantId , pageLink , transportType ) ;
}
}
@Cacheable ( cacheNames = DEVICE_PROFILE_CACHE , key = "{#tenantId.id, #name}" )
@Override
@Override
public DeviceProfile findOrCreateDeviceProfile ( TenantId tenantId , String name ) {
public DeviceProfile findOrCreateDeviceProfile ( TenantId tenantId , String name ) {
log . trace ( "Executing findOrCreateDefaultDeviceProfile" ) ;
log . trace ( "Executing findOrCreateDefaultDeviceProfile" ) ;
@ -207,6 +220,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
return deviceProfile ;
return deviceProfile ;
}
}
@Transactional ( propagation = Propagation . SUPPORTS )
@Override
@Override
public DeviceProfile createDefaultDeviceProfile ( TenantId tenantId ) {
public DeviceProfile createDefaultDeviceProfile ( TenantId tenantId ) {
log . trace ( "Executing createDefaultDeviceProfile tenantId [{}]" , tenantId ) ;
log . trace ( "Executing createDefaultDeviceProfile tenantId [{}]" , tenantId ) ;
@ -234,56 +248,49 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
return saveDeviceProfile ( deviceProfile ) ;
return saveDeviceProfile ( deviceProfile ) ;
}
}
@Cacheable ( cacheNames = DEVICE_PROFILE_CACHE , key = "{'default', #tenantId.id}" )
@Override
@Override
public DeviceProfile findDefaultDeviceProfile ( TenantId tenantId ) {
public DeviceProfile findDefaultDeviceProfile ( TenantId tenantId ) {
log . trace ( "Executing findDefaultDeviceProfile tenantId [{}]" , tenantId ) ;
log . trace ( "Executing findDefaultDeviceProfile tenantId [{}]" , tenantId ) ;
validateId ( tenantId , INCORRECT_TENANT_ID + tenantId ) ;
validateId ( tenantId , INCORRECT_TENANT_ID + tenantId ) ;
return deviceProfileDao . findDefaultDeviceProfile ( tenantId ) ;
return cache . getAndPutInTransaction ( DeviceProfileCacheKey . defaultProfile ( tenantId ) ,
( ) - > deviceProfileDao . findDefaultDeviceProfile ( tenantId ) , true ) ;
}
}
@Cacheable ( cacheNames = DEVICE_PROFILE_CACHE , key = "{'default', 'info', #tenantId.id}" )
@Override
@Override
public DeviceProfileInfo findDefaultDeviceProfileInfo ( TenantId tenantId ) {
public DeviceProfileInfo findDefaultDeviceProfileInfo ( TenantId tenantId ) {
log . trace ( "Executing findDefaultDeviceProfileInfo tenantId [{}]" , tenantId ) ;
log . trace ( "Executing findDefaultDeviceProfileInfo tenantId [{}]" , tenantId ) ;
validateId ( tenantId , INCORRECT_TENANT_ID + tenantId ) ;
validateId ( tenantId , INCORRECT_TENANT_ID + tenantId ) ;
return deviceProfileDao . findDefaultDeviceProfileInfo ( tenantId ) ;
return toDeviceProfileInfo ( findDefaultDeviceProfile ( tenantId ) ) ;
}
}
@Transactional ( propagation = Propagation . SUPPORTS )
@Override
@Override
public boolean setDefaultDeviceProfile ( TenantId tenantId , DeviceProfileId deviceProfileId ) {
public boolean setDefaultDeviceProfile ( TenantId tenantId , DeviceProfileId deviceProfileId ) {
log . trace ( "Executing setDefaultDeviceProfile [{}]" , deviceProfileId ) ;
log . trace ( "Executing setDefaultDeviceProfile [{}]" , deviceProfileId ) ;
Validator . validateId ( deviceProfileId , INCORRECT_DEVICE_PROFILE_ID + deviceProfileId ) ;
Validator . validateId ( deviceProfileId , INCORRECT_DEVICE_PROFILE_ID + deviceProfileId ) ;
DeviceProfile deviceProfile = deviceProfileDao . findById ( tenantId , deviceProfileId . getId ( ) ) ;
DeviceProfile deviceProfile = deviceProfileDao . findById ( tenantId , deviceProfileId . getId ( ) ) ;
if ( ! deviceProfile . isDefault ( ) ) {
if ( ! deviceProfile . isDefault ( ) ) {
Cache cache = cacheManager . getCache ( DEVICE_PROFILE_CACHE ) ;
deviceProfile . setDefault ( true ) ;
deviceProfile . setDefault ( true ) ;
DeviceProfile previousDefaultDeviceProfile = findDefaultDeviceProfile ( tenantId ) ;
DeviceProfile previousDefaultDeviceProfile = findDefaultDeviceProfile ( tenantId ) ;
boolean changed = false ;
boolean changed = false ;
if ( previousDefaultDeviceProfile = = null ) {
if ( previousDefaultDeviceProfile = = null ) {
deviceProfileDao . save ( tenantId , deviceProfile ) ;
deviceProfileDao . save ( tenantId , deviceProfile ) ;
publishEvictEvent ( new DeviceProfileEvictEvent ( deviceProfile . getTenantId ( ) , deviceProfile . getName ( ) , null , deviceProfile . getId ( ) , true ) ) ;
changed = true ;
changed = true ;
} else if ( ! previousDefaultDeviceProfile . getId ( ) . equals ( deviceProfile . getId ( ) ) ) {
} else if ( ! previousDefaultDeviceProfile . getId ( ) . equals ( deviceProfile . getId ( ) ) ) {
previousDefaultDeviceProfile . setDefault ( false ) ;
previousDefaultDeviceProfile . setDefault ( false ) ;
deviceProfileDao . save ( tenantId , previousDefaultDeviceProfile ) ;
deviceProfileDao . save ( tenantId , previousDefaultDeviceProfile ) ;
deviceProfileDao . save ( tenantId , deviceProfile ) ;
deviceProfileDao . save ( tenantId , deviceProfile ) ;
cache . evict ( Collections . singletonList ( previousDefaultDeviceProfile . getId ( ) . getId ( ) ) ) ;
publishEvictEvent ( new DeviceProfileEvictEvent ( previousDefaultDeviceProfile . getTenantId ( ) , previousDefaultDeviceProfile . getName ( ) , null , previousDefaultDeviceProfile . getId ( ) , false ) ) ;
cache . evict ( Arrays . asList ( "info" , previousDefaultDeviceProfile . getId ( ) . getId ( ) ) ) ;
publishEvictEvent ( new DeviceProfileEvictEvent ( deviceProfile . getTenantId ( ) , deviceProfile . getName ( ) , null , deviceProfile . getId ( ) , true ) ) ;
cache . evict ( Arrays . asList ( tenantId . getId ( ) , previousDefaultDeviceProfile . getName ( ) ) ) ;
changed = true ;
changed = true ;
}
}
if ( changed ) {
cache . evict ( Collections . singletonList ( deviceProfile . getId ( ) . getId ( ) ) ) ;
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 ;
return changed ;
}
}
return false ;
return false ;
}
}
@Transactional ( propagation = Propagation . SUPPORTS )
@Override
@Override
public void deleteDeviceProfilesByTenantId ( TenantId tenantId ) {
public void deleteDeviceProfilesByTenantId ( TenantId tenantId ) {
log . trace ( "Executing deleteDeviceProfilesByTenantId, tenantId [{}]" , tenantId ) ;
log . trace ( "Executing deleteDeviceProfilesByTenantId, tenantId [{}]" , tenantId ) ;
@ -305,4 +312,9 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
}
}
} ;
} ;
private DeviceProfileInfo toDeviceProfileInfo ( DeviceProfile profile ) {
return profile = = null ? null : new DeviceProfileInfo ( profile . getId ( ) , profile . getName ( ) , profile . getImage ( ) ,
profile . getDefaultDashboardId ( ) , profile . getType ( ) , profile . getTransportType ( ) ) ;
}
}
}