Put to cache after save for versioned entities
This commit is contained in:
parent
4302b63fd9
commit
d0546ae83c
@ -54,6 +54,11 @@ public abstract class CaffeineTbTransactionalCache<K extends Serializable, V ext
|
||||
return SimpleTbCacheValueWrapper.wrap(cache.get(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbCacheValueWrapper<V> get(K key, boolean transactionMode) {
|
||||
return get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V value) {
|
||||
lock.lock();
|
||||
|
||||
@ -31,7 +31,7 @@ public class RedisTbCacheTransaction<K extends Serializable, V extends Serializa
|
||||
|
||||
@Override
|
||||
public void put(K key, V value) {
|
||||
cache.put(key, value, connection);
|
||||
cache.put(key, value, connection, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -77,9 +77,14 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend
|
||||
|
||||
@Override
|
||||
public TbCacheValueWrapper<V> get(K key) {
|
||||
return get(key, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbCacheValueWrapper<V> get(K key, boolean transactionMode) {
|
||||
try (var connection = connectionFactory.getConnection()) {
|
||||
byte[] rawKey = getRawKey(key);
|
||||
byte[] rawValue = doGet(connection, rawKey);
|
||||
byte[] rawValue = doGet(connection, rawKey, transactionMode);
|
||||
if (rawValue == null || rawValue.length == 0) {
|
||||
return null;
|
||||
} else if (Arrays.equals(rawValue, BINARY_NULL_VALUE)) {
|
||||
@ -96,18 +101,18 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend
|
||||
}
|
||||
}
|
||||
|
||||
protected byte[] doGet(RedisConnection connection, byte[] rawKey) {
|
||||
protected byte[] doGet(RedisConnection connection, byte[] rawKey, boolean transactionMode) {
|
||||
return connection.stringCommands().get(rawKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V value) {
|
||||
try (var connection = connectionFactory.getConnection()) {
|
||||
put(key, value, connection);
|
||||
put(key, value, connection, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void put(K key, V value, RedisConnection connection) {
|
||||
public void put(K key, V value, RedisConnection connection, boolean transactionMode) {
|
||||
put(connection, key, value, RedisStringCommands.SetOption.UPSERT);
|
||||
}
|
||||
|
||||
|
||||
@ -27,6 +27,8 @@ public interface TbTransactionalCache<K extends Serializable, V extends Serializ
|
||||
|
||||
TbCacheValueWrapper<V> get(K key);
|
||||
|
||||
TbCacheValueWrapper<V> get(K key, boolean transactionMode);
|
||||
|
||||
void put(K key, V value);
|
||||
|
||||
void putIfAbsent(K key, V value);
|
||||
@ -60,7 +62,7 @@ public interface TbTransactionalCache<K extends Serializable, V extends Serializ
|
||||
}
|
||||
|
||||
default V getAndPutInTransaction(K key, Supplier<V> dbCall, boolean cacheNullValue) {
|
||||
TbCacheValueWrapper<V> cacheValueWrapper = get(key);
|
||||
TbCacheValueWrapper<V> cacheValueWrapper = get(key, true);
|
||||
if (cacheValueWrapper != null) {
|
||||
return cacheValueWrapper.get();
|
||||
}
|
||||
@ -95,7 +97,7 @@ public interface TbTransactionalCache<K extends Serializable, V extends Serializ
|
||||
}
|
||||
|
||||
default <R> R getAndPutInTransaction(K key, Supplier<R> dbCall, Function<V, R> cacheValueToResult, Function<R, V> dbValueToCacheValue, boolean cacheNullValue) {
|
||||
TbCacheValueWrapper<V> cacheValueWrapper = get(key);
|
||||
TbCacheValueWrapper<V> cacheValueWrapper = get(key, true);
|
||||
if (cacheValueWrapper != null) {
|
||||
var cacheValue = cacheValueWrapper.get();
|
||||
return cacheValue == null ? null : cacheValueToResult.apply(cacheValue);
|
||||
|
||||
@ -88,7 +88,10 @@ public abstract class VersionedRedisTbCache<K extends Serializable, V extends Se
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] doGet(RedisConnection connection, byte[] rawKey) {
|
||||
protected byte[] doGet(RedisConnection connection, byte[] rawKey, boolean transactionMode) {
|
||||
if (transactionMode) {
|
||||
return super.doGet(connection, rawKey, true);
|
||||
}
|
||||
return connection.stringCommands().getRange(rawKey, VERSION_SIZE, VALUE_END_OFFSET);
|
||||
}
|
||||
|
||||
@ -104,7 +107,11 @@ public abstract class VersionedRedisTbCache<K extends Serializable, V extends Se
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V value, RedisConnection connection) {
|
||||
public void put(K key, V value, RedisConnection connection, boolean transactionMode) {
|
||||
if (transactionMode) {
|
||||
super.put(key, value, connection, true); // because scripting commands are not supported in transaction mode
|
||||
return;
|
||||
}
|
||||
Long version = value != null ? value.getVersion() : 0;
|
||||
byte[] rawKey = getRawKey(key);
|
||||
doPut(rawKey, value, version, cacheTtl, connection);
|
||||
|
||||
@ -27,11 +27,17 @@ public interface VersionedTbCache<K extends Serializable, V extends Serializable
|
||||
TbCacheValueWrapper<V> get(K key);
|
||||
|
||||
default V get(K key, Supplier<V> supplier) {
|
||||
return get(key, supplier, true);
|
||||
}
|
||||
|
||||
default V get(K key, Supplier<V> supplier, boolean putToCache) {
|
||||
return Optional.ofNullable(get(key))
|
||||
.map(TbCacheValueWrapper::get)
|
||||
.orElseGet(() -> {
|
||||
V value = supplier.get();
|
||||
put(key, value);
|
||||
if (putToCache) {
|
||||
put(key, value);
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
package org.thingsboard.server.cache.device;
|
||||
|
||||
import lombok.Data;
|
||||
import org.thingsboard.server.common.data.Device;
|
||||
import org.thingsboard.server.common.data.id.DeviceId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
|
||||
@ -26,5 +27,6 @@ public class DeviceCacheEvictEvent {
|
||||
private final DeviceId deviceId;
|
||||
private final String newName;
|
||||
private final String oldName;
|
||||
private Device savedDevice;
|
||||
|
||||
}
|
||||
|
||||
@ -18,13 +18,13 @@ package org.thingsboard.server.cache.device;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.cache.CaffeineTbTransactionalCache;
|
||||
import org.thingsboard.server.cache.VersionedCaffeineTbCache;
|
||||
import org.thingsboard.server.common.data.CacheConstants;
|
||||
import org.thingsboard.server.common.data.Device;
|
||||
|
||||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true)
|
||||
@Service("DeviceCache")
|
||||
public class DeviceCaffeineCache extends CaffeineTbTransactionalCache<DeviceCacheKey, Device> {
|
||||
public class DeviceCaffeineCache extends VersionedCaffeineTbCache<DeviceCacheKey, Device> {
|
||||
|
||||
public DeviceCaffeineCache(CacheManager cacheManager) {
|
||||
super(cacheManager, CacheConstants.DEVICE_CACHE);
|
||||
|
||||
@ -21,9 +21,9 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.serializer.SerializationException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.cache.CacheSpecsMap;
|
||||
import org.thingsboard.server.cache.RedisTbTransactionalCache;
|
||||
import org.thingsboard.server.cache.TBRedisCacheConfiguration;
|
||||
import org.thingsboard.server.cache.TbRedisSerializer;
|
||||
import org.thingsboard.server.cache.VersionedRedisTbCache;
|
||||
import org.thingsboard.server.common.data.CacheConstants;
|
||||
import org.thingsboard.server.common.data.Device;
|
||||
import org.thingsboard.server.common.util.ProtoUtils;
|
||||
@ -31,7 +31,7 @@ import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
|
||||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis")
|
||||
@Service("DeviceCache")
|
||||
public class DeviceRedisCache extends RedisTbTransactionalCache<DeviceCacheKey, Device> {
|
||||
public class DeviceRedisCache extends VersionedRedisTbCache<DeviceCacheKey, Device> {
|
||||
|
||||
public DeviceRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) {
|
||||
super(CacheConstants.DEVICE_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbRedisSerializer<>() {
|
||||
|
||||
@ -38,15 +38,15 @@ public class AssetProfileCacheKey implements Serializable {
|
||||
this.defaultProfile = defaultProfile;
|
||||
}
|
||||
|
||||
public static AssetProfileCacheKey fromName(TenantId tenantId, String name) {
|
||||
public static AssetProfileCacheKey forName(TenantId tenantId, String name) {
|
||||
return new AssetProfileCacheKey(tenantId, name, null, false);
|
||||
}
|
||||
|
||||
public static AssetProfileCacheKey fromId(AssetProfileId id) {
|
||||
public static AssetProfileCacheKey forId(AssetProfileId id) {
|
||||
return new AssetProfileCacheKey(null, null, id, false);
|
||||
}
|
||||
|
||||
public static AssetProfileCacheKey defaultProfile(TenantId tenantId) {
|
||||
public static AssetProfileCacheKey forDefaultProfile(TenantId tenantId) {
|
||||
return new AssetProfileCacheKey(tenantId, null, null, true);
|
||||
}
|
||||
|
||||
|
||||
@ -18,13 +18,13 @@ package org.thingsboard.server.dao.asset;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.cache.CaffeineTbTransactionalCache;
|
||||
import org.thingsboard.server.cache.VersionedCaffeineTbCache;
|
||||
import org.thingsboard.server.common.data.CacheConstants;
|
||||
import org.thingsboard.server.common.data.asset.AssetProfile;
|
||||
|
||||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true)
|
||||
@Service("AssetProfileCache")
|
||||
public class AssetProfileCaffeineCache extends CaffeineTbTransactionalCache<AssetProfileCacheKey, AssetProfile> {
|
||||
public class AssetProfileCaffeineCache extends VersionedCaffeineTbCache<AssetProfileCacheKey, AssetProfile> {
|
||||
|
||||
public AssetProfileCaffeineCache(CacheManager cacheManager) {
|
||||
super(cacheManager, CacheConstants.ASSET_PROFILE_CACHE);
|
||||
|
||||
@ -15,11 +15,16 @@
|
||||
*/
|
||||
package org.thingsboard.server.dao.asset;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.thingsboard.server.common.data.asset.AssetProfile;
|
||||
import org.thingsboard.server.common.data.id.AssetProfileId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
|
||||
@Data
|
||||
@RequiredArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AssetProfileEvictEvent {
|
||||
|
||||
private final TenantId tenantId;
|
||||
@ -27,5 +32,6 @@ public class AssetProfileEvictEvent {
|
||||
private final String oldName;
|
||||
private final AssetProfileId assetProfileId;
|
||||
private final boolean defaultProfile;
|
||||
private AssetProfile savedAssetProfile;
|
||||
|
||||
}
|
||||
|
||||
@ -19,17 +19,18 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.cache.CacheSpecsMap;
|
||||
import org.thingsboard.server.cache.RedisTbTransactionalCache;
|
||||
import org.thingsboard.server.cache.TBRedisCacheConfiguration;
|
||||
import org.thingsboard.server.cache.TbJsonRedisSerializer;
|
||||
import org.thingsboard.server.cache.VersionedRedisTbCache;
|
||||
import org.thingsboard.server.common.data.CacheConstants;
|
||||
import org.thingsboard.server.common.data.asset.AssetProfile;
|
||||
|
||||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis")
|
||||
@Service("AssetProfileCache")
|
||||
public class AssetProfileRedisCache extends RedisTbTransactionalCache<AssetProfileCacheKey, AssetProfile> {
|
||||
public class AssetProfileRedisCache extends VersionedRedisTbCache<AssetProfileCacheKey, AssetProfile> {
|
||||
|
||||
public AssetProfileRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) {
|
||||
super(CacheConstants.ASSET_PROFILE_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbJsonRedisSerializer<>(AssetProfile.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ import org.thingsboard.server.common.data.id.HasId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.page.PageData;
|
||||
import org.thingsboard.server.common.data.page.PageLink;
|
||||
import org.thingsboard.server.dao.entity.AbstractCachedEntityService;
|
||||
import org.thingsboard.server.dao.entity.CachedVersionedEntityService;
|
||||
import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent;
|
||||
import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent;
|
||||
import org.thingsboard.server.dao.exception.DataValidationException;
|
||||
@ -53,7 +53,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId;
|
||||
|
||||
@Service("AssetProfileDaoService")
|
||||
@Slf4j
|
||||
public class AssetProfileServiceImpl extends AbstractCachedEntityService<AssetProfileCacheKey, AssetProfile, AssetProfileEvictEvent> implements AssetProfileService {
|
||||
public class AssetProfileServiceImpl extends CachedVersionedEntityService<AssetProfileCacheKey, AssetProfile, AssetProfileEvictEvent> implements AssetProfileService {
|
||||
|
||||
private static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
|
||||
|
||||
@ -81,18 +81,20 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService<AssetPr
|
||||
@TransactionalEventListener(classes = AssetProfileEvictEvent.class)
|
||||
@Override
|
||||
public void handleEvictEvent(AssetProfileEvictEvent event) {
|
||||
List<AssetProfileCacheKey> keys = new ArrayList<>(2);
|
||||
keys.add(AssetProfileCacheKey.fromName(event.getTenantId(), event.getNewName()));
|
||||
if (event.getAssetProfileId() != null) {
|
||||
keys.add(AssetProfileCacheKey.fromId(event.getAssetProfileId()));
|
||||
List<AssetProfileCacheKey> toEvict = new ArrayList<>(2);
|
||||
toEvict.add(AssetProfileCacheKey.forName(event.getTenantId(), event.getNewName()));
|
||||
if (event.getSavedAssetProfile() != null) {
|
||||
cache.put(AssetProfileCacheKey.forId(event.getSavedAssetProfile().getId()), event.getSavedAssetProfile());
|
||||
} else if (event.getAssetProfileId() != null) {
|
||||
toEvict.add(AssetProfileCacheKey.forId(event.getAssetProfileId()));
|
||||
}
|
||||
if (event.isDefaultProfile()) {
|
||||
keys.add(AssetProfileCacheKey.defaultProfile(event.getTenantId()));
|
||||
toEvict.add(AssetProfileCacheKey.forDefaultProfile(event.getTenantId()));
|
||||
}
|
||||
if (StringUtils.isNotEmpty(event.getOldName()) && !event.getOldName().equals(event.getNewName())) {
|
||||
keys.add(AssetProfileCacheKey.fromName(event.getTenantId(), event.getOldName()));
|
||||
toEvict.add(AssetProfileCacheKey.forName(event.getTenantId(), event.getOldName()));
|
||||
}
|
||||
cache.evict(keys);
|
||||
cache.evict(toEvict);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -104,8 +106,8 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService<AssetPr
|
||||
public AssetProfile findAssetProfileById(TenantId tenantId, AssetProfileId assetProfileId, boolean putInCache) {
|
||||
log.trace("Executing findAssetProfileById [{}]", assetProfileId);
|
||||
Validator.validateId(assetProfileId, id -> INCORRECT_ASSET_PROFILE_ID + id);
|
||||
return cache.getOrFetchFromDB(AssetProfileCacheKey.fromId(assetProfileId),
|
||||
() -> assetProfileDao.findById(tenantId, assetProfileId.getId()), true, putInCache);
|
||||
return cache.get(AssetProfileCacheKey.forId(assetProfileId),
|
||||
() -> assetProfileDao.findById(tenantId, assetProfileId.getId()), putInCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -117,7 +119,7 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService<AssetPr
|
||||
public AssetProfile findAssetProfileByName(TenantId tenantId, String profileName, boolean putInCache) {
|
||||
log.trace("Executing findAssetProfileByName [{}][{}]", tenantId, profileName);
|
||||
Validator.validateString(profileName, s -> INCORRECT_ASSET_PROFILE_NAME + s);
|
||||
return cache.getOrFetchFromDB(AssetProfileCacheKey.fromName(tenantId, profileName),
|
||||
return cache.getOrFetchFromDB(AssetProfileCacheKey.forName(tenantId, profileName),
|
||||
() -> assetProfileDao.findByName(tenantId, profileName), false, putInCache);
|
||||
}
|
||||
|
||||
@ -147,7 +149,7 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService<AssetPr
|
||||
imageService.replaceBase64WithImageUrl(assetProfile, "asset profile");
|
||||
savedAssetProfile = assetProfileDao.saveAndFlush(assetProfile.getTenantId(), assetProfile);
|
||||
publishEvictEvent(new AssetProfileEvictEvent(savedAssetProfile.getTenantId(), savedAssetProfile.getName(),
|
||||
oldAssetProfile != null ? oldAssetProfile.getName() : null, savedAssetProfile.getId(), savedAssetProfile.isDefault()));
|
||||
oldAssetProfile != null ? oldAssetProfile.getName() : null, savedAssetProfile.getId(), savedAssetProfile.isDefault(), savedAssetProfile));
|
||||
if (publishSaveEvent) {
|
||||
eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(savedAssetProfile.getTenantId()).entity(savedAssetProfile)
|
||||
.entityId(savedAssetProfile.getId()).created(oldAssetProfile == null).build());
|
||||
@ -267,7 +269,7 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService<AssetPr
|
||||
public AssetProfile findDefaultAssetProfile(TenantId tenantId) {
|
||||
log.trace("Executing findDefaultAssetProfile tenantId [{}]", tenantId);
|
||||
validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
|
||||
return cache.getAndPutInTransaction(AssetProfileCacheKey.defaultProfile(tenantId),
|
||||
return cache.getAndPutInTransaction(AssetProfileCacheKey.forDefaultProfile(tenantId),
|
||||
() -> assetProfileDao.findDefaultAssetProfile(tenantId), true);
|
||||
}
|
||||
|
||||
@ -353,4 +355,5 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService<AssetPr
|
||||
return profile == null ? null : new AssetProfileInfo(profile.getId(), profile.getTenantId(), profile.getName(), profile.getImage(),
|
||||
profile.getDefaultDashboardId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -16,11 +16,11 @@
|
||||
package org.thingsboard.server.dao.device;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.leshan.core.SecurityMode;
|
||||
import org.eclipse.leshan.core.util.SecurityUtil;
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.event.TransactionalEventListener;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
@ -45,20 +45,18 @@ import org.thingsboard.server.dao.entity.AbstractCachedEntityService;
|
||||
import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent;
|
||||
import org.thingsboard.server.dao.exception.DataValidationException;
|
||||
import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException;
|
||||
import org.thingsboard.server.dao.service.DataValidator;
|
||||
import org.thingsboard.server.dao.service.validator.DeviceCredentialsDataValidator;
|
||||
|
||||
import static org.thingsboard.server.dao.service.Validator.validateId;
|
||||
import static org.thingsboard.server.dao.service.Validator.validateString;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class DeviceCredentialsServiceImpl extends AbstractCachedEntityService<String, DeviceCredentials, DeviceCredentialsEvictEvent> implements DeviceCredentialsService {
|
||||
|
||||
@Autowired
|
||||
private DeviceCredentialsDao deviceCredentialsDao;
|
||||
|
||||
@Autowired
|
||||
private DataValidator<DeviceCredentials> credentialsValidator;
|
||||
private final DeviceCredentialsDao deviceCredentialsDao;
|
||||
private final DeviceCredentialsDataValidator credentialsValidator;
|
||||
|
||||
@TransactionalEventListener(classes = DeviceCredentialsEvictEvent.class)
|
||||
@Override
|
||||
|
||||
@ -41,19 +41,19 @@ public class DeviceProfileCacheKey implements Serializable {
|
||||
this.provisionDeviceKey = provisionDeviceKey;
|
||||
}
|
||||
|
||||
public static DeviceProfileCacheKey fromName(TenantId tenantId, String name) {
|
||||
public static DeviceProfileCacheKey forName(TenantId tenantId, String name) {
|
||||
return new DeviceProfileCacheKey(tenantId, name, null, false, null);
|
||||
}
|
||||
|
||||
public static DeviceProfileCacheKey fromId(DeviceProfileId id) {
|
||||
public static DeviceProfileCacheKey forId(DeviceProfileId id) {
|
||||
return new DeviceProfileCacheKey(null, null, id, false, null);
|
||||
}
|
||||
|
||||
public static DeviceProfileCacheKey defaultProfile(TenantId tenantId) {
|
||||
public static DeviceProfileCacheKey forDefaultProfile(TenantId tenantId) {
|
||||
return new DeviceProfileCacheKey(tenantId, null, null, true, null);
|
||||
}
|
||||
|
||||
public static DeviceProfileCacheKey fromProvisionDeviceKey(String provisionDeviceKey) {
|
||||
public static DeviceProfileCacheKey forProvisionKey(String provisionDeviceKey) {
|
||||
return new DeviceProfileCacheKey(null, null, null, false, provisionDeviceKey);
|
||||
}
|
||||
|
||||
|
||||
@ -18,13 +18,13 @@ package org.thingsboard.server.dao.device;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.cache.CaffeineTbTransactionalCache;
|
||||
import org.thingsboard.server.cache.VersionedCaffeineTbCache;
|
||||
import org.thingsboard.server.common.data.CacheConstants;
|
||||
import org.thingsboard.server.common.data.DeviceProfile;
|
||||
|
||||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true)
|
||||
@Service("DeviceProfileCache")
|
||||
public class DeviceProfileCaffeineCache extends CaffeineTbTransactionalCache<DeviceProfileCacheKey, DeviceProfile> {
|
||||
public class DeviceProfileCaffeineCache extends VersionedCaffeineTbCache<DeviceProfileCacheKey, DeviceProfile> {
|
||||
|
||||
public DeviceProfileCaffeineCache(CacheManager cacheManager) {
|
||||
super(cacheManager, CacheConstants.DEVICE_PROFILE_CACHE);
|
||||
|
||||
@ -15,11 +15,16 @@
|
||||
*/
|
||||
package org.thingsboard.server.dao.device;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.thingsboard.server.common.data.DeviceProfile;
|
||||
import org.thingsboard.server.common.data.id.DeviceProfileId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
|
||||
@Data
|
||||
@RequiredArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DeviceProfileEvictEvent {
|
||||
|
||||
private final TenantId tenantId;
|
||||
@ -28,5 +33,6 @@ public class DeviceProfileEvictEvent {
|
||||
private final DeviceProfileId deviceProfileId;
|
||||
private final boolean defaultProfile;
|
||||
private final String provisionDeviceKey;
|
||||
private DeviceProfile savedDeviceProfile;
|
||||
|
||||
}
|
||||
|
||||
@ -21,9 +21,9 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.serializer.SerializationException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.cache.CacheSpecsMap;
|
||||
import org.thingsboard.server.cache.RedisTbTransactionalCache;
|
||||
import org.thingsboard.server.cache.TBRedisCacheConfiguration;
|
||||
import org.thingsboard.server.cache.TbRedisSerializer;
|
||||
import org.thingsboard.server.cache.VersionedRedisTbCache;
|
||||
import org.thingsboard.server.common.data.CacheConstants;
|
||||
import org.thingsboard.server.common.data.DeviceProfile;
|
||||
import org.thingsboard.server.common.util.ProtoUtils;
|
||||
@ -31,7 +31,7 @@ import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
|
||||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis")
|
||||
@Service("DeviceProfileCache")
|
||||
public class DeviceProfileRedisCache extends RedisTbTransactionalCache<DeviceProfileCacheKey, DeviceProfile> {
|
||||
public class DeviceProfileRedisCache extends VersionedRedisTbCache<DeviceProfileCacheKey, DeviceProfile> {
|
||||
|
||||
public DeviceProfileRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) {
|
||||
super(CacheConstants.DEVICE_PROFILE_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbRedisSerializer<DeviceProfileCacheKey, DeviceProfile>() {
|
||||
@ -50,4 +50,5 @@ public class DeviceProfileRedisCache extends RedisTbTransactionalCache<DevicePro
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -15,8 +15,8 @@
|
||||
*/
|
||||
package org.thingsboard.server.dao.device;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@ -42,14 +42,14 @@ import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.page.PageData;
|
||||
import org.thingsboard.server.common.data.page.PageLink;
|
||||
import org.thingsboard.server.common.msg.EncryptionUtil;
|
||||
import org.thingsboard.server.dao.entity.AbstractCachedEntityService;
|
||||
import org.thingsboard.server.dao.entity.CachedVersionedEntityService;
|
||||
import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent;
|
||||
import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent;
|
||||
import org.thingsboard.server.dao.exception.DataValidationException;
|
||||
import org.thingsboard.server.dao.resource.ImageService;
|
||||
import org.thingsboard.server.dao.service.DataValidator;
|
||||
import org.thingsboard.server.dao.service.PaginatedRemover;
|
||||
import org.thingsboard.server.dao.service.Validator;
|
||||
import org.thingsboard.server.dao.service.validator.DeviceProfileDataValidator;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.security.cert.Certificate;
|
||||
@ -69,7 +69,8 @@ import static org.thingsboard.server.dao.service.Validator.validateString;
|
||||
|
||||
@Service("DeviceProfileDaoService")
|
||||
@Slf4j
|
||||
public class DeviceProfileServiceImpl extends AbstractCachedEntityService<DeviceProfileCacheKey, DeviceProfile, DeviceProfileEvictEvent> implements DeviceProfileService {
|
||||
@RequiredArgsConstructor
|
||||
public class DeviceProfileServiceImpl extends CachedVersionedEntityService<DeviceProfileCacheKey, DeviceProfile, DeviceProfileEvictEvent> implements DeviceProfileService {
|
||||
|
||||
private static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
|
||||
private static final String INCORRECT_DEVICE_PROFILE_ID = "Incorrect deviceProfileId ";
|
||||
@ -87,7 +88,7 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
|
||||
private DeviceService deviceService;
|
||||
|
||||
@Autowired
|
||||
private DataValidator<DeviceProfile> deviceProfileValidator;
|
||||
private DeviceProfileDataValidator deviceProfileValidator;
|
||||
|
||||
@Autowired
|
||||
private ImageService imageService;
|
||||
@ -95,21 +96,23 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
|
||||
@TransactionalEventListener(classes = DeviceProfileEvictEvent.class)
|
||||
@Override
|
||||
public void handleEvictEvent(DeviceProfileEvictEvent event) {
|
||||
List<DeviceProfileCacheKey> keys = new ArrayList<>(2);
|
||||
keys.add(DeviceProfileCacheKey.fromName(event.getTenantId(), event.getNewName()));
|
||||
if (event.getDeviceProfileId() != null) {
|
||||
keys.add(DeviceProfileCacheKey.fromId(event.getDeviceProfileId()));
|
||||
List<DeviceProfileCacheKey> toEvict = new ArrayList<>(2);
|
||||
toEvict.add(DeviceProfileCacheKey.forName(event.getTenantId(), event.getNewName()));
|
||||
if (event.getSavedDeviceProfile() != null) {
|
||||
cache.put(DeviceProfileCacheKey.forId(event.getSavedDeviceProfile().getId()), event.getSavedDeviceProfile());
|
||||
} else if (event.getDeviceProfileId() != null) {
|
||||
toEvict.add(DeviceProfileCacheKey.forId(event.getDeviceProfileId()));
|
||||
}
|
||||
if (event.isDefaultProfile()) {
|
||||
keys.add(DeviceProfileCacheKey.defaultProfile(event.getTenantId()));
|
||||
toEvict.add(DeviceProfileCacheKey.forDefaultProfile(event.getTenantId()));
|
||||
}
|
||||
if (StringUtils.isNotEmpty(event.getOldName()) && !event.getOldName().equals(event.getNewName())) {
|
||||
keys.add(DeviceProfileCacheKey.fromName(event.getTenantId(), event.getOldName()));
|
||||
toEvict.add(DeviceProfileCacheKey.forName(event.getTenantId(), event.getOldName()));
|
||||
}
|
||||
if (StringUtils.isNotEmpty(event.getProvisionDeviceKey())) {
|
||||
keys.add(DeviceProfileCacheKey.fromProvisionDeviceKey(event.getProvisionDeviceKey()));
|
||||
toEvict.add(DeviceProfileCacheKey.forProvisionKey(event.getProvisionDeviceKey()));
|
||||
}
|
||||
cache.evict(keys);
|
||||
cache.evict(toEvict);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -121,8 +124,8 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
|
||||
public DeviceProfile findDeviceProfileById(TenantId tenantId, DeviceProfileId deviceProfileId, boolean putInCache) {
|
||||
log.trace("Executing findDeviceProfileById [{}]", deviceProfileId);
|
||||
validateId(deviceProfileId, id -> INCORRECT_DEVICE_PROFILE_ID + id);
|
||||
return cache.getOrFetchFromDB(DeviceProfileCacheKey.fromId(deviceProfileId),
|
||||
() -> deviceProfileDao.findById(tenantId, deviceProfileId.getId()), true, putInCache);
|
||||
return cache.get(DeviceProfileCacheKey.forId(deviceProfileId),
|
||||
() -> deviceProfileDao.findById(tenantId, deviceProfileId.getId()), putInCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -134,7 +137,7 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
|
||||
public DeviceProfile findDeviceProfileByName(TenantId tenantId, String profileName, boolean putInCache) {
|
||||
log.trace("Executing findDeviceProfileByName [{}][{}]", tenantId, profileName);
|
||||
validateString(profileName, pn -> INCORRECT_DEVICE_PROFILE_NAME + pn);
|
||||
return cache.getOrFetchFromDB(DeviceProfileCacheKey.fromName(tenantId, profileName),
|
||||
return cache.getOrFetchFromDB(DeviceProfileCacheKey.forName(tenantId, profileName),
|
||||
() -> deviceProfileDao.findByName(tenantId, profileName), true, putInCache);
|
||||
}
|
||||
|
||||
@ -142,7 +145,7 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
|
||||
public DeviceProfile findDeviceProfileByProvisionDeviceKey(String provisionDeviceKey) {
|
||||
log.trace("Executing findDeviceProfileByProvisionDeviceKey provisionKey [{}]", provisionDeviceKey);
|
||||
validateString(provisionDeviceKey, dk -> INCORRECT_PROVISION_DEVICE_KEY + dk);
|
||||
return cache.getAndPutInTransaction(DeviceProfileCacheKey.fromProvisionDeviceKey(provisionDeviceKey),
|
||||
return cache.getAndPutInTransaction(DeviceProfileCacheKey.forProvisionKey(provisionDeviceKey),
|
||||
() -> deviceProfileDao.findByProvisionDeviceKey(provisionDeviceKey), false);
|
||||
}
|
||||
|
||||
@ -179,7 +182,7 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
|
||||
savedDeviceProfile = deviceProfileDao.saveAndFlush(deviceProfile.getTenantId(), deviceProfile);
|
||||
publishEvictEvent(new DeviceProfileEvictEvent(savedDeviceProfile.getTenantId(), savedDeviceProfile.getName(),
|
||||
oldDeviceProfile != null ? oldDeviceProfile.getName() : null, savedDeviceProfile.getId(), savedDeviceProfile.isDefault(),
|
||||
oldDeviceProfile != null ? oldDeviceProfile.getProvisionDeviceKey() : null));
|
||||
oldDeviceProfile != null ? oldDeviceProfile.getProvisionDeviceKey() : null, savedDeviceProfile));
|
||||
if (publishSaveEvent) {
|
||||
eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(savedDeviceProfile.getTenantId()).entityId(savedDeviceProfile.getId())
|
||||
.entity(savedDeviceProfile).oldEntity(oldDeviceProfile).created(oldDeviceProfile == null).build());
|
||||
@ -241,13 +244,9 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
|
||||
null, deviceProfile.getId(), deviceProfile.isDefault(),
|
||||
deviceProfile.getProvisionDeviceKey()));
|
||||
eventPublisher.publishEvent(DeleteEntityEvent.builder().tenantId(tenantId).entityId(deviceProfileId).entity(deviceProfile).build());
|
||||
} catch (Exception t) {
|
||||
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
|
||||
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_device_profile")) {
|
||||
throw new DataValidationException("The device profile referenced by the devices cannot be deleted!");
|
||||
} else {
|
||||
throw t;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
checkConstraintViolation(e, "fk_device_profile", "The device profile referenced by the devices cannot be deleted!");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@ -316,7 +315,7 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
|
||||
public DeviceProfile findDefaultDeviceProfile(TenantId tenantId) {
|
||||
log.trace("Executing findDefaultDeviceProfile tenantId [{}]", tenantId);
|
||||
validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
|
||||
return cache.getAndPutInTransaction(DeviceProfileCacheKey.defaultProfile(tenantId),
|
||||
return cache.getAndPutInTransaction(DeviceProfileCacheKey.forDefaultProfile(tenantId),
|
||||
() -> deviceProfileDao.findDefaultDeviceProfile(tenantId), true);
|
||||
}
|
||||
|
||||
|
||||
@ -18,8 +18,8 @@ package org.thingsboard.server.dao.device;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.event.TransactionalEventListener;
|
||||
@ -68,7 +68,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentialsType;
|
||||
import org.thingsboard.server.dao.device.provision.ProvisionFailedException;
|
||||
import org.thingsboard.server.dao.device.provision.ProvisionRequest;
|
||||
import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus;
|
||||
import org.thingsboard.server.dao.entity.AbstractCachedEntityService;
|
||||
import org.thingsboard.server.dao.entity.CachedVersionedEntityService;
|
||||
import org.thingsboard.server.dao.entity.EntityCountService;
|
||||
import org.thingsboard.server.dao.event.EventService;
|
||||
import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent;
|
||||
@ -76,8 +76,8 @@ import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent;
|
||||
import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent;
|
||||
import org.thingsboard.server.dao.exception.DataValidationException;
|
||||
import org.thingsboard.server.dao.exception.IncorrectParameterException;
|
||||
import org.thingsboard.server.dao.service.DataValidator;
|
||||
import org.thingsboard.server.dao.service.PaginatedRemover;
|
||||
import org.thingsboard.server.dao.service.validator.DeviceDataValidator;
|
||||
import org.thingsboard.server.dao.sql.JpaExecutorService;
|
||||
import org.thingsboard.server.dao.tenant.TenantService;
|
||||
|
||||
@ -94,38 +94,23 @@ import static org.thingsboard.server.dao.service.Validator.validateString;
|
||||
|
||||
@Service("DeviceDaoService")
|
||||
@Slf4j
|
||||
public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKey, Device, DeviceCacheEvictEvent> implements DeviceService {
|
||||
@RequiredArgsConstructor
|
||||
public class DeviceServiceImpl extends CachedVersionedEntityService<DeviceCacheKey, Device, DeviceCacheEvictEvent> implements DeviceService {
|
||||
|
||||
public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
|
||||
public static final String INCORRECT_DEVICE_PROFILE_ID = "Incorrect deviceProfileId ";
|
||||
public static final String INCORRECT_PAGE_LINK = "Incorrect page link ";
|
||||
public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId ";
|
||||
public static final String INCORRECT_DEVICE_ID = "Incorrect deviceId ";
|
||||
public static final String INCORRECT_EDGE_ID = "Incorrect edgeId ";
|
||||
|
||||
@Autowired
|
||||
private DeviceDao deviceDao;
|
||||
|
||||
@Autowired
|
||||
private DeviceCredentialsService deviceCredentialsService;
|
||||
|
||||
@Autowired
|
||||
private DeviceProfileService deviceProfileService;
|
||||
|
||||
@Autowired
|
||||
private EventService eventService;
|
||||
|
||||
@Autowired
|
||||
private TenantService tenantService;
|
||||
|
||||
@Autowired
|
||||
private DataValidator<Device> deviceValidator;
|
||||
|
||||
@Autowired
|
||||
private EntityCountService countService;
|
||||
|
||||
@Autowired
|
||||
private JpaExecutorService executor;
|
||||
private final DeviceDao deviceDao;
|
||||
private final DeviceCredentialsService deviceCredentialsService;
|
||||
private final DeviceProfileService deviceProfileService;
|
||||
private final EventService eventService;
|
||||
private final TenantService tenantService;
|
||||
private final DeviceDataValidator deviceValidator;
|
||||
private final EntityCountService countService;
|
||||
private final JpaExecutorService executor;
|
||||
|
||||
@Override
|
||||
public DeviceInfo findDeviceInfoById(TenantId tenantId, DeviceId deviceId) {
|
||||
@ -139,11 +124,11 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
|
||||
log.trace("Executing findDeviceById [{}]", deviceId);
|
||||
validateId(deviceId, id -> INCORRECT_DEVICE_ID + id);
|
||||
if (TenantId.SYS_TENANT_ID.equals(tenantId)) {
|
||||
return cache.getAndPutInTransaction(new DeviceCacheKey(deviceId),
|
||||
() -> deviceDao.findById(tenantId, deviceId.getId()), true);
|
||||
return cache.get(new DeviceCacheKey(deviceId),
|
||||
() -> deviceDao.findById(tenantId, deviceId.getId()));
|
||||
} else {
|
||||
return cache.getAndPutInTransaction(new DeviceCacheKey(tenantId, deviceId),
|
||||
() -> deviceDao.findDeviceByTenantIdAndId(tenantId, deviceId.getId()), true);
|
||||
return cache.get(new DeviceCacheKey(tenantId, deviceId),
|
||||
() -> deviceDao.findDeviceByTenantIdAndId(tenantId, deviceId.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -251,12 +236,13 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
|
||||
device.setType(deviceProfile.getName());
|
||||
device.setDeviceData(syncDeviceData(deviceProfile, device.getDeviceData()));
|
||||
Device savedDevice = deviceDao.saveAndFlush(device.getTenantId(), device);
|
||||
publishEvictEvent(deviceCacheEvictEvent);
|
||||
if (device.getId() == null) {
|
||||
countService.publishCountEntityEvictEvent(savedDevice.getTenantId(), EntityType.DEVICE);
|
||||
}
|
||||
eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(savedDevice.getTenantId()).entityId(savedDevice.getId())
|
||||
.entity(savedDevice).oldEntity(oldDevice).created(device.getId() == null).build());
|
||||
deviceCacheEvictEvent.setSavedDevice(savedDevice);
|
||||
publishEvictEvent(deviceCacheEvictEvent);
|
||||
return savedDevice;
|
||||
} catch (Exception t) {
|
||||
handleEvictEvent(deviceCacheEvictEvent);
|
||||
@ -270,16 +256,20 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
|
||||
@TransactionalEventListener(classes = DeviceCacheEvictEvent.class)
|
||||
@Override
|
||||
public void handleEvictEvent(DeviceCacheEvictEvent event) {
|
||||
List<DeviceCacheKey> keys = new ArrayList<>(3);
|
||||
keys.add(new DeviceCacheKey(event.getTenantId(), event.getNewName()));
|
||||
if (event.getDeviceId() != null) {
|
||||
keys.add(new DeviceCacheKey(event.getDeviceId()));
|
||||
keys.add(new DeviceCacheKey(event.getTenantId(), event.getDeviceId()));
|
||||
}
|
||||
List<DeviceCacheKey> toEvict = new ArrayList<>(3);
|
||||
toEvict.add(new DeviceCacheKey(event.getTenantId(), event.getNewName()));
|
||||
if (StringUtils.isNotEmpty(event.getOldName()) && !event.getOldName().equals(event.getNewName())) {
|
||||
keys.add(new DeviceCacheKey(event.getTenantId(), event.getOldName()));
|
||||
toEvict.add(new DeviceCacheKey(event.getTenantId(), event.getOldName()));
|
||||
}
|
||||
cache.evict(keys);
|
||||
Device savedDevice = event.getSavedDevice();
|
||||
if (savedDevice != null) {
|
||||
cache.put(new DeviceCacheKey(event.getDeviceId()), savedDevice);
|
||||
cache.put(new DeviceCacheKey(event.getTenantId(), event.getDeviceId()), savedDevice);
|
||||
} else {
|
||||
toEvict.add(new DeviceCacheKey(event.getDeviceId()));
|
||||
toEvict.add(new DeviceCacheKey(event.getTenantId(), event.getDeviceId()));
|
||||
}
|
||||
cache.evict(toEvict);
|
||||
}
|
||||
|
||||
private DeviceData syncDeviceData(DeviceProfile deviceProfile, DeviceData deviceData) {
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright © 2016-2024 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.dao.entity;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.thingsboard.server.cache.VersionedTbCache;
|
||||
import org.thingsboard.server.common.data.HasVersion;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public abstract class CachedVersionedEntityService<K extends Serializable, V extends Serializable & HasVersion, E> extends AbstractCachedEntityService<K, V, E> {
|
||||
|
||||
@Autowired
|
||||
protected VersionedTbCache<K, V> cache;
|
||||
|
||||
}
|
||||
@ -19,6 +19,7 @@ import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import org.thingsboard.server.common.data.EntityView;
|
||||
import org.thingsboard.server.common.data.HasVersion;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
@ -26,11 +27,16 @@ import java.util.List;
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
@Builder
|
||||
public class EntityViewCacheValue implements Serializable {
|
||||
public class EntityViewCacheValue implements Serializable, HasVersion {
|
||||
|
||||
private static final long serialVersionUID = 1959004642076413174L;
|
||||
|
||||
private final EntityView entityView;
|
||||
private final List<EntityView> entityViews;
|
||||
|
||||
@Override
|
||||
public Long getVersion() {
|
||||
return entityView != null ? entityView.getVersion() : 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -18,12 +18,12 @@ package org.thingsboard.server.dao.entityview;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.cache.CaffeineTbTransactionalCache;
|
||||
import org.thingsboard.server.cache.VersionedCaffeineTbCache;
|
||||
import org.thingsboard.server.common.data.CacheConstants;
|
||||
|
||||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true)
|
||||
@Service("EntityViewCache")
|
||||
public class EntityViewCaffeineCache extends CaffeineTbTransactionalCache<EntityViewCacheKey, EntityViewCacheValue> {
|
||||
public class EntityViewCaffeineCache extends VersionedCaffeineTbCache<EntityViewCacheKey, EntityViewCacheValue> {
|
||||
|
||||
public EntityViewCaffeineCache(CacheManager cacheManager) {
|
||||
super(cacheManager, CacheConstants.ENTITY_VIEW_CACHE);
|
||||
|
||||
@ -15,21 +15,25 @@
|
||||
*/
|
||||
package org.thingsboard.server.dao.entityview;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.thingsboard.server.common.data.EntityView;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.EntityViewId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
|
||||
@Data
|
||||
@RequiredArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class EntityViewEvictEvent {
|
||||
|
||||
private final TenantId tenantId;
|
||||
private final EntityViewId id;
|
||||
private final EntityViewId entityViewId;
|
||||
private final EntityId newEntityId;
|
||||
private final EntityId oldEntityId;
|
||||
private final String newName;
|
||||
private final String oldName;
|
||||
private EntityView savedEntityView;
|
||||
|
||||
}
|
||||
|
||||
@ -19,14 +19,14 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.cache.CacheSpecsMap;
|
||||
import org.thingsboard.server.cache.RedisTbTransactionalCache;
|
||||
import org.thingsboard.server.cache.TBRedisCacheConfiguration;
|
||||
import org.thingsboard.server.cache.TbJsonRedisSerializer;
|
||||
import org.thingsboard.server.cache.VersionedRedisTbCache;
|
||||
import org.thingsboard.server.common.data.CacheConstants;
|
||||
|
||||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis")
|
||||
@Service("EntityViewCache")
|
||||
public class EntityViewRedisCache extends RedisTbTransactionalCache<EntityViewCacheKey, EntityViewCacheValue> {
|
||||
public class EntityViewRedisCache extends VersionedRedisTbCache<EntityViewCacheKey, EntityViewCacheValue> {
|
||||
|
||||
public EntityViewRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) {
|
||||
super(CacheConstants.ENTITY_VIEW_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbJsonRedisSerializer<>(EntityViewCacheValue.class));
|
||||
|
||||
@ -19,6 +19,7 @@ import com.google.common.base.Function;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import jakarta.annotation.Nullable;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -43,16 +44,15 @@ import org.thingsboard.server.common.data.page.PageLink;
|
||||
import org.thingsboard.server.common.data.relation.EntityRelation;
|
||||
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
|
||||
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
|
||||
import org.thingsboard.server.dao.entity.AbstractCachedEntityService;
|
||||
import org.thingsboard.server.dao.entity.CachedVersionedEntityService;
|
||||
import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent;
|
||||
import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent;
|
||||
import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent;
|
||||
import org.thingsboard.server.dao.exception.DataValidationException;
|
||||
import org.thingsboard.server.dao.service.DataValidator;
|
||||
import org.thingsboard.server.dao.service.PaginatedRemover;
|
||||
import org.thingsboard.server.dao.service.validator.EntityViewDataValidator;
|
||||
import org.thingsboard.server.dao.sql.JpaExecutorService;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@ -69,7 +69,7 @@ import static org.thingsboard.server.dao.service.Validator.validateString;
|
||||
*/
|
||||
@Service("EntityViewDaoService")
|
||||
@Slf4j
|
||||
public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityViewCacheKey, EntityViewCacheValue, EntityViewEvictEvent> implements EntityViewService {
|
||||
public class EntityViewServiceImpl extends CachedVersionedEntityService<EntityViewCacheKey, EntityViewCacheValue, EntityViewEvictEvent> implements EntityViewService {
|
||||
|
||||
public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
|
||||
public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId ";
|
||||
@ -80,7 +80,7 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
|
||||
private EntityViewDao entityViewDao;
|
||||
|
||||
@Autowired
|
||||
private DataValidator<EntityView> entityViewValidator;
|
||||
private EntityViewDataValidator entityViewValidator;
|
||||
|
||||
@Autowired
|
||||
protected JpaExecutorService service;
|
||||
@ -88,17 +88,21 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
|
||||
@TransactionalEventListener(classes = EntityViewEvictEvent.class)
|
||||
@Override
|
||||
public void handleEvictEvent(EntityViewEvictEvent event) {
|
||||
List<EntityViewCacheKey> keys = new ArrayList<>(5);
|
||||
keys.add(EntityViewCacheKey.byName(event.getTenantId(), event.getNewName()));
|
||||
keys.add(EntityViewCacheKey.byId(event.getId()));
|
||||
keys.add(EntityViewCacheKey.byEntityId(event.getTenantId(), event.getNewEntityId()));
|
||||
List<EntityViewCacheKey> toEvict = new ArrayList<>(5);
|
||||
toEvict.add(EntityViewCacheKey.byName(event.getTenantId(), event.getNewName()));
|
||||
if (event.getSavedEntityView() != null) {
|
||||
cache.put(EntityViewCacheKey.byId(event.getSavedEntityView().getId()), new EntityViewCacheValue(event.getSavedEntityView(), null));
|
||||
} else if (event.getEntityViewId() != null) {
|
||||
toEvict.add(EntityViewCacheKey.byId(event.getEntityViewId()));
|
||||
}
|
||||
toEvict.add(EntityViewCacheKey.byEntityId(event.getTenantId(), event.getNewEntityId()));
|
||||
if (event.getOldEntityId() != null && !event.getOldEntityId().equals(event.getNewEntityId())) {
|
||||
keys.add(EntityViewCacheKey.byEntityId(event.getTenantId(), event.getOldEntityId()));
|
||||
toEvict.add(EntityViewCacheKey.byEntityId(event.getTenantId(), event.getOldEntityId()));
|
||||
}
|
||||
if (StringUtils.isNotEmpty(event.getOldName()) && !event.getOldName().equals(event.getNewName())) {
|
||||
keys.add(EntityViewCacheKey.byName(event.getTenantId(), event.getOldName()));
|
||||
toEvict.add(EntityViewCacheKey.byName(event.getTenantId(), event.getOldName()));
|
||||
}
|
||||
cache.evict(keys);
|
||||
cache.evict(toEvict);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -113,11 +117,11 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
|
||||
if (doValidate) {
|
||||
old = entityViewValidator.validate(entityView, EntityView::getTenantId);
|
||||
} else if (entityView.getId() != null) {
|
||||
old = findEntityViewById(entityView.getTenantId(), entityView.getId());
|
||||
old = findEntityViewById(entityView.getTenantId(), entityView.getId(), false);
|
||||
}
|
||||
try {
|
||||
EntityView saved = entityViewDao.save(entityView.getTenantId(), entityView);
|
||||
publishEvictEvent(new EntityViewEvictEvent(saved.getTenantId(), saved.getId(), saved.getEntityId(), old != null ? old.getEntityId() : null, saved.getName(), old != null ? old.getName() : null));
|
||||
publishEvictEvent(new EntityViewEvictEvent(saved.getTenantId(), saved.getId(), saved.getEntityId(), old != null ? old.getEntityId() : null, saved.getName(), old != null ? old.getName() : null, saved));
|
||||
eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(saved.getTenantId())
|
||||
.entityId(saved.getId()).created(entityView.getId() == null).build());
|
||||
return saved;
|
||||
@ -172,9 +176,11 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
|
||||
public EntityView findEntityViewById(TenantId tenantId, EntityViewId entityViewId, boolean putInCache) {
|
||||
log.trace("Executing findEntityViewById [{}]", entityViewId);
|
||||
validateId(entityViewId, id -> INCORRECT_ENTITY_VIEW_ID + id);
|
||||
return cache.getOrFetchFromDB(EntityViewCacheKey.byId(entityViewId),
|
||||
() -> entityViewDao.findById(tenantId, entityViewId.getId())
|
||||
, EntityViewCacheValue::getEntityView, v -> new EntityViewCacheValue(v, null), true, putInCache);
|
||||
EntityViewCacheValue value = cache.get(EntityViewCacheKey.byId(entityViewId), () -> {
|
||||
EntityView entityView = entityViewDao.findById(tenantId, entityViewId.getId());
|
||||
return new EntityViewCacheValue(entityView, null);
|
||||
}, putInCache);
|
||||
return value != null ? value.getEntityView() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -233,7 +239,7 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
|
||||
PageLink pageLink) {
|
||||
log.trace("Executing findEntityViewByTenantIdAndCustomerId, tenantId [{}], customerId [{}]," +
|
||||
" pageLink [{}]", tenantId, customerId, pageLink);
|
||||
validateId(tenantId, id ->INCORRECT_TENANT_ID + id);
|
||||
validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
|
||||
validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
|
||||
validatePageLink(pageLink);
|
||||
return entityViewDao.findEntityViewsByTenantIdAndCustomerId(tenantId.getId(),
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
package org.thingsboard.server.dao.service.validator;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.server.common.data.Device;
|
||||
import org.thingsboard.server.common.data.StringUtils;
|
||||
@ -32,7 +33,7 @@ public class DeviceCredentialsDataValidator extends DataValidator<DeviceCredenti
|
||||
@Autowired
|
||||
private DeviceCredentialsDao deviceCredentialsDao;
|
||||
|
||||
@Autowired
|
||||
@Autowired @Lazy
|
||||
private DeviceService deviceService;
|
||||
|
||||
@Override
|
||||
|
||||
@ -79,7 +79,7 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
|
||||
try {
|
||||
entity = doSave(entity, isNew);
|
||||
} catch (OptimisticLockException e) {
|
||||
throw new EntityVersionMismatchException("The entity was already changed by someone else", e);
|
||||
throw new EntityVersionMismatchException((getEntityType() != null ? getEntityType().getNormalName() : "Entity") + " was already changed by someone else", e);
|
||||
}
|
||||
return DaoUtil.getData(entity);
|
||||
}
|
||||
@ -145,7 +145,9 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
|
||||
@Override
|
||||
@Transactional
|
||||
public void removeById(TenantId tenantId, UUID id) {
|
||||
getRepository().deleteById(id);
|
||||
JpaRepository<E, UUID> repository = getRepository();
|
||||
repository.deleteById(id);
|
||||
repository.flush();
|
||||
log.debug("Remove request: {}", id);
|
||||
}
|
||||
|
||||
@ -153,6 +155,7 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
|
||||
public void removeAllByIds(Collection<UUID> ids) {
|
||||
JpaRepository<E, UUID> repository = getRepository();
|
||||
ids.forEach(repository::deleteById);
|
||||
repository.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user