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 602128818b..97061d9bc7 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 @@ -292,7 +292,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D } private PaginatedRemover tenantDeviceProfilesRemover = - new PaginatedRemover() { + new PaginatedRemover<>() { @Override protected PageData findEntities(TenantId tenantId, TenantId id, PageLink pageLink) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java index 2e386c4c31..414b33d3c2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java @@ -133,7 +133,6 @@ public class EdgeServiceImpl extends AbstractCachedEntityService implements OtaPackageService { public static final String INCORRECT_OTA_PACKAGE_ID = "Incorrect otaPackageId "; public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; private final OtaPackageDao otaPackageDao; private final OtaPackageInfoDao otaPackageInfoDao; - private final CacheManager cacheManager; private final OtaPackageDataCache otaPackageDataCache; private final DataValidator otaPackageInfoValidator; private final DataValidator otaPackageValidator; + @TransactionalEventListener(classes = OtaPackageCacheEvictEvent.class) + @Override + public void handleEvictEvent(OtaPackageCacheEvictEvent event) { + cache.evict(new OtaPackageCacheKey(event.getId())); + otaPackageDataCache.evict(event.getId().toString()); + } + + @Transactional(propagation = Propagation.SUPPORTS) @Override public OtaPackageInfo saveOtaPackageInfo(OtaPackageInfo otaPackageInfo, boolean isUrl) { log.trace("Executing saveOtaPackageInfo [{}]", otaPackageInfo); - if(isUrl && (StringUtils.isEmpty(otaPackageInfo.getUrl()) || otaPackageInfo.getUrl().trim().length() == 0)) { + if (isUrl && (StringUtils.isEmpty(otaPackageInfo.getUrl()) || otaPackageInfo.getUrl().trim().length() == 0)) { throw new DataValidationException("Ota package URL should be specified!"); } otaPackageInfoValidator.validate(otaPackageInfo, OtaPackageInfo::getTenantId); try { OtaPackageId otaPackageId = otaPackageInfo.getId(); + var result = otaPackageInfoDao.save(otaPackageInfo.getTenantId(), otaPackageInfo); if (otaPackageId != null) { - Cache cache = cacheManager.getCache(OTA_PACKAGE_CACHE); - cache.evict(toOtaPackageInfoKey(otaPackageId)); - otaPackageDataCache.evict(otaPackageId.toString()); + publishEvictEvent(new OtaPackageCacheEvictEvent(otaPackageId)); } - return otaPackageInfoDao.save(otaPackageInfo.getTenantId(), otaPackageInfo); + return result; } catch (Exception t) { ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("ota_package_tenant_title_version_unq_key")) { @@ -88,18 +94,18 @@ public class BaseOtaPackageService implements OtaPackageService { } } + @Transactional(propagation = Propagation.SUPPORTS) @Override public OtaPackage saveOtaPackage(OtaPackage otaPackage) { log.trace("Executing saveOtaPackage [{}]", otaPackage); otaPackageValidator.validate(otaPackage, OtaPackageInfo::getTenantId); try { OtaPackageId otaPackageId = otaPackage.getId(); + var result = otaPackageDao.save(otaPackage.getTenantId(), otaPackage); if (otaPackageId != null) { - Cache cache = cacheManager.getCache(OTA_PACKAGE_CACHE); - cache.evict(toOtaPackageInfoKey(otaPackageId)); - otaPackageDataCache.evict(otaPackageId.toString()); + publishEvictEvent(new OtaPackageCacheEvictEvent(otaPackageId)); } - return otaPackageDao.save(otaPackage.getTenantId(), otaPackage); + return result; } catch (Exception t) { ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("ota_package_tenant_title_version_unq_key")) { @@ -149,11 +155,11 @@ public class BaseOtaPackageService implements OtaPackageService { } @Override - @Cacheable(cacheNames = OTA_PACKAGE_CACHE, key = "{#otaPackageId}") public OtaPackageInfo findOtaPackageInfoById(TenantId tenantId, OtaPackageId otaPackageId) { log.trace("Executing findOtaPackageInfoById [{}]", otaPackageId); validateId(otaPackageId, INCORRECT_OTA_PACKAGE_ID + otaPackageId); - return otaPackageInfoDao.findById(tenantId, otaPackageId.getId()); + return cache.getAndPutInTransaction(new OtaPackageCacheKey(otaPackageId), + () -> otaPackageInfoDao.findById(tenantId, otaPackageId.getId()), true); } @Override @@ -179,15 +185,14 @@ public class BaseOtaPackageService implements OtaPackageService { return otaPackageInfoDao.findOtaPackageInfoByTenantIdAndDeviceProfileIdAndTypeAndHasData(tenantId, deviceProfileId, otaPackageType, pageLink); } + @Transactional(propagation = Propagation.SUPPORTS) @Override public void deleteOtaPackage(TenantId tenantId, OtaPackageId otaPackageId) { log.trace("Executing deleteOtaPackage [{}]", otaPackageId); validateId(otaPackageId, INCORRECT_OTA_PACKAGE_ID + otaPackageId); try { - Cache cache = cacheManager.getCache(OTA_PACKAGE_CACHE); - cache.evict(toOtaPackageInfoKey(otaPackageId)); - otaPackageDataCache.evict(otaPackageId.toString()); otaPackageDao.removeById(tenantId, otaPackageId.getId()); + publishEvictEvent(new OtaPackageCacheEvictEvent(otaPackageId)); } catch (Exception t) { ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_firmware_device")) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageCacheEvictEvent.java b/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageCacheEvictEvent.java new file mode 100644 index 0000000000..cea1c1afcb --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageCacheEvictEvent.java @@ -0,0 +1,29 @@ +/** + * Copyright © 2016-2022 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.ota; + +import lombok.Data; +import lombok.RequiredArgsConstructor; +import org.thingsboard.server.common.data.id.OtaPackageId; +import org.thingsboard.server.common.data.id.TenantId; + +@Data +@RequiredArgsConstructor +class OtaPackageCacheEvictEvent { + + private final OtaPackageId id; + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageCacheKey.java b/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageCacheKey.java new file mode 100644 index 0000000000..b3acbea6bd --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageCacheKey.java @@ -0,0 +1,41 @@ +/** + * Copyright © 2016-2022 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.ota; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.thingsboard.server.cache.CacheKeyUtil; +import org.thingsboard.server.common.data.id.OtaPackageId; +import org.thingsboard.server.common.data.id.TenantId; + +import java.io.Serializable; + +@Getter +@EqualsAndHashCode +@RequiredArgsConstructor +@Builder +public class OtaPackageCacheKey implements Serializable { + + private final OtaPackageId id; + + @Override + public String toString() { + return id.getId().toString(); + } + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageCaffeineCache.java b/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageCaffeineCache.java new file mode 100644 index 0000000000..03f2401f42 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageCaffeineCache.java @@ -0,0 +1,35 @@ +/** + * Copyright © 2016-2022 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.ota; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cache.CacheManager; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.CacheConstants; +import org.thingsboard.server.common.data.OtaPackageInfo; +import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.dao.asset.AssetCacheKey; +import org.thingsboard.server.dao.cache.CaffeineTbTransactionalCache; + +@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true) +@Service("OtaPackageCache") +public class OtaPackageCaffeineCache extends CaffeineTbTransactionalCache { + + public OtaPackageCaffeineCache(CacheManager cacheManager) { + super(cacheManager, CacheConstants.OTA_PACKAGE_CACHE); + } + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageRedisCache.java b/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageRedisCache.java new file mode 100644 index 0000000000..7605f24f3c --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageRedisCache.java @@ -0,0 +1,37 @@ +/** + * Copyright © 2016-2022 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.ota; + +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.TBRedisCacheConfiguration; +import org.thingsboard.server.common.data.CacheConstants; +import org.thingsboard.server.common.data.OtaPackageInfo; +import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.dao.asset.AssetCacheKey; +import org.thingsboard.server.dao.cache.RedisTbTransactionalCache; +import org.thingsboard.server.dao.cache.TbRedisSerializer; + +@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") +@Service("OtaPackageCache") +public class OtaPackageRedisCache extends RedisTbTransactionalCache { + + public OtaPackageRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) { + super(CacheConstants.OTA_PACKAGE_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbRedisSerializer<>()); + } +}