diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/CacheKeyUtil.java b/common/cache/src/main/java/org/thingsboard/server/cache/CacheKeyUtil.java deleted file mode 100644 index 1c1a096f59..0000000000 --- a/common/cache/src/main/java/org/thingsboard/server/cache/CacheKeyUtil.java +++ /dev/null @@ -1,41 +0,0 @@ -/** - * 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.cache; - -public class CacheKeyUtil { - - public static String toString(Object... keyElements) { - StringBuilder sb = new StringBuilder(); - boolean first = true; - for (Object keyElement : keyElements) { - first = addElement(sb, first, keyElement); - } - return sb.toString(); - } - - private static boolean addElement(StringBuilder sb, boolean first, Object element) { - if (element != null) { - if (!first) { - sb.append("_"); - } - sb.append(element); - return false; - } else { - return first; - } - } - -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetCacheKey.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetCacheKey.java index 70e17e28ff..c4a6d5b7fb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetCacheKey.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetCacheKey.java @@ -19,8 +19,6 @@ 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.DeviceId; import org.thingsboard.server.common.data.id.TenantId; import java.io.Serializable; @@ -31,12 +29,14 @@ import java.io.Serializable; @Builder public class AssetCacheKey implements Serializable { + private static final long serialVersionUID = 4196610233744512673L; + private final TenantId tenantId; private final String name; @Override public String toString() { - return CacheKeyUtil.toString(tenantId, name); + return tenantId + "_" + name; } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCacheKey.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCacheKey.java index 574a5c2617..6e62a07e1b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCacheKey.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCacheKey.java @@ -19,7 +19,6 @@ 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.DeviceId; import org.thingsboard.server.common.data.id.TenantId; @@ -45,7 +44,11 @@ public class DeviceCacheKey implements Serializable { @Override public String toString() { - return CacheKeyUtil.toString(tenantId, deviceId, deviceName); + if (deviceId != null) { + return tenantId + "_" + deviceId; + } else { + return tenantId + "_n_" + deviceName; + } } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileCacheKey.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileCacheKey.java new file mode 100644 index 0000000000..79f997e22c --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileCacheKey.java @@ -0,0 +1,63 @@ +/** + * 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.device; + +import lombok.Data; +import org.thingsboard.server.common.data.id.DeviceProfileId; +import org.thingsboard.server.common.data.id.TenantId; + +import java.io.Serializable; + +@Data +public class DeviceProfileCacheKey implements Serializable { + + private static final long serialVersionUID = 8220455917177676472L; + + private final TenantId tenantId; + private final String name; + private final DeviceProfileId deviceProfileId; + private final boolean defaultProfile; + + private DeviceProfileCacheKey(TenantId tenantId, String name, DeviceProfileId deviceProfileId, boolean defaultProfile) { + this.tenantId = tenantId; + this.name = name; + this.deviceProfileId = deviceProfileId; + this.defaultProfile = defaultProfile; + } + + public static DeviceProfileCacheKey fromName(TenantId tenantId, String name) { + return new DeviceProfileCacheKey(tenantId, name, null, false); + } + + public static DeviceProfileCacheKey fromId(DeviceProfileId id) { + return new DeviceProfileCacheKey(null, null, id, false); + } + + public static DeviceProfileCacheKey defaultProfile(TenantId tenantId) { + return new DeviceProfileCacheKey(tenantId, null, null, true); + } + + @Override + public String toString() { + if (deviceProfileId != null) { + return deviceProfileId.toString(); + } else if (defaultProfile) { + return tenantId.toString(); + } else { + return tenantId + "_" + name; + } + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileCaffeineCache.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileCaffeineCache.java new file mode 100644 index 0000000000..03c5e43f94 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileCaffeineCache.java @@ -0,0 +1,34 @@ +/** + * 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.device; + +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.Device; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.dao.cache.CaffeineTbTransactionalCache; + +@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true) +@Service("DeviceProfileCache") +public class DeviceProfileCaffeineCache extends CaffeineTbTransactionalCache { + + public DeviceProfileCaffeineCache(CacheManager cacheManager) { + super(cacheManager, CacheConstants.DEVICE_PROFILE_CACHE); + } + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileEvictEvent.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileEvictEvent.java new file mode 100644 index 0000000000..b5b4b27a6b --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileEvictEvent.java @@ -0,0 +1,31 @@ +/** + * 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.device; + +import lombok.Data; +import org.thingsboard.server.common.data.id.DeviceProfileId; +import org.thingsboard.server.common.data.id.TenantId; + +@Data +public class DeviceProfileEvictEvent { + + private final TenantId tenantId; + private final String newName; + private final String oldName; + private final DeviceProfileId deviceProfileId; + private final boolean defaultProfile; + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileRedisCache.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileRedisCache.java new file mode 100644 index 0000000000..8d0c4eded0 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileRedisCache.java @@ -0,0 +1,36 @@ +/** + * 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.device; + +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.Device; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.dao.cache.RedisTbTransactionalCache; +import org.thingsboard.server.dao.cache.TbRedisSerializer; + +@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") +@Service("DeviceProfileCache") +public class DeviceProfileRedisCache extends RedisTbTransactionalCache { + + public DeviceProfileRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) { + super(CacheConstants.DEVICE_PROFILE_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbRedisSerializer<>()); + } +} 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 97061d9bc7..229e9c316f 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 @@ -17,17 +17,23 @@ package org.thingsboard.server.dao.device; import lombok.extern.slf4j.Slf4j; import org.hibernate.exception.ConstraintViolationException; +import org.jetbrains.annotations.Nullable; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.Cacheable; 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.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfileInfo; import org.thingsboard.server.common.data.DeviceProfileProvisionType; import org.thingsboard.server.common.data.DeviceProfileType; 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.DefaultDeviceProfileTransportConfiguration; 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.page.PageData; 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.exception.DataValidationException; 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.tenant.TenantProfileCacheKey; +import org.thingsboard.server.dao.tenant.TenantProfileEvictEvent; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -52,7 +64,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId; @Service @Slf4j -public class DeviceProfileServiceImpl extends AbstractEntityService implements DeviceProfileService { +public class DeviceProfileServiceImpl extends AbstractCachedEntityService implements DeviceProfileService { private static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; private static final String INCORRECT_DEVICE_PROFILE_ID = "Incorrect deviceProfileId "; @@ -67,51 +79,60 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @Autowired private DeviceService deviceService; - @Autowired - private CacheManager cacheManager; - @Autowired private DataValidator deviceProfileValidator; 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 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 public DeviceProfile findDeviceProfileById(TenantId tenantId, DeviceProfileId deviceProfileId) { log.trace("Executing findDeviceProfileById [{}]", 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 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); + return cache.getAndPutInTransaction(DeviceProfileCacheKey.fromName(tenantId, profileName), + () -> deviceProfileDao.findByName(tenantId, profileName), true); } - @Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{'info', #deviceProfileId.id}") @Override public DeviceProfileInfo findDeviceProfileInfoById(TenantId tenantId, DeviceProfileId deviceProfileId) { log.trace("Executing findDeviceProfileById [{}]", deviceProfileId); Validator.validateId(deviceProfileId, INCORRECT_DEVICE_PROFILE_ID + deviceProfileId); - return deviceProfileDao.findDeviceProfileInfoById(tenantId, deviceProfileId.getId()); + return toDeviceProfileInfo(findDeviceProfileById(tenantId, deviceProfileId)); } @Override 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 oldDeviceProfile = deviceProfileValidator.validate(deviceProfile, DeviceProfile::getTenantId); DeviceProfile savedDeviceProfile; try { savedDeviceProfile = deviceProfileDao.saveAndFlush(deviceProfile.getTenantId(), deviceProfile); } catch (Exception t) { ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); 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!"); } 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!"); @@ -119,14 +140,8 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D throw t; } } - 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())); - } + publishEvictEvent(new DeviceProfileEvictEvent(savedDeviceProfile.getTenantId(), savedDeviceProfile.getName(), + oldDeviceProfile != null ? oldDeviceProfile.getName() : null, savedDeviceProfile.getId(), savedDeviceProfile.isDefault())); if (oldDeviceProfile != null && !oldDeviceProfile.getName().equals(deviceProfile.getName())) { PageLink pageLink = new PageLink(100); PageData pageData; @@ -142,6 +157,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D return savedDeviceProfile; } + @Transactional(propagation = Propagation.SUPPORTS) @Override public void deleteDeviceProfile(TenantId tenantId, DeviceProfileId deviceProfileId) { log.trace("Executing deleteDeviceProfile [{}]", deviceProfileId); @@ -157,6 +173,8 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D DeviceProfileId deviceProfileId = deviceProfile.getId(); try { deviceProfileDao.removeById(tenantId, deviceProfileId.getId()); + publishEvictEvent(new DeviceProfileEvictEvent(deviceProfile.getTenantId(), deviceProfile.getName(), + null, deviceProfile.getId(), deviceProfile.isDefault())); } catch (Exception t) { ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); 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); - 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 @@ -188,7 +202,6 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D return deviceProfileDao.findDeviceProfileInfos(tenantId, pageLink, transportType); } - @Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{#tenantId.id, #name}") @Override public DeviceProfile findOrCreateDeviceProfile(TenantId tenantId, String name) { log.trace("Executing findOrCreateDefaultDeviceProfile"); @@ -207,6 +220,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D return deviceProfile; } + @Transactional(propagation = Propagation.SUPPORTS) @Override public DeviceProfile createDefaultDeviceProfile(TenantId tenantId) { log.trace("Executing createDefaultDeviceProfile tenantId [{}]", tenantId); @@ -234,56 +248,49 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D return saveDeviceProfile(deviceProfile); } - @Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{'default', #tenantId.id}") @Override public DeviceProfile findDefaultDeviceProfile(TenantId tenantId) { log.trace("Executing findDefaultDeviceProfile tenantId [{}]", 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 public DeviceProfileInfo findDefaultDeviceProfileInfo(TenantId tenantId) { log.trace("Executing findDefaultDeviceProfileInfo tenantId [{}]", tenantId); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - return deviceProfileDao.findDefaultDeviceProfileInfo(tenantId); + return toDeviceProfileInfo(findDefaultDeviceProfile(tenantId)); } + @Transactional(propagation = Propagation.SUPPORTS) @Override public boolean setDefaultDeviceProfile(TenantId tenantId, DeviceProfileId deviceProfileId) { log.trace("Executing setDefaultDeviceProfile [{}]", deviceProfileId); Validator.validateId(deviceProfileId, INCORRECT_DEVICE_PROFILE_ID + deviceProfileId); DeviceProfile deviceProfile = deviceProfileDao.findById(tenantId, deviceProfileId.getId()); if (!deviceProfile.isDefault()) { - Cache cache = cacheManager.getCache(DEVICE_PROFILE_CACHE); deviceProfile.setDefault(true); DeviceProfile previousDefaultDeviceProfile = findDefaultDeviceProfile(tenantId); boolean changed = false; if (previousDefaultDeviceProfile == null) { deviceProfileDao.save(tenantId, deviceProfile); + publishEvictEvent(new DeviceProfileEvictEvent(deviceProfile.getTenantId(), deviceProfile.getName(), null, deviceProfile.getId(), true)); changed = true; } else if (!previousDefaultDeviceProfile.getId().equals(deviceProfile.getId())) { previousDefaultDeviceProfile.setDefault(false); deviceProfileDao.save(tenantId, previousDefaultDeviceProfile); 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())); + publishEvictEvent(new DeviceProfileEvictEvent(previousDefaultDeviceProfile.getTenantId(), previousDefaultDeviceProfile.getName(), null, previousDefaultDeviceProfile.getId(), false)); + publishEvictEvent(new DeviceProfileEvictEvent(deviceProfile.getTenantId(), deviceProfile.getName(), null, deviceProfile.getId(), 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 false; } + @Transactional(propagation = Propagation.SUPPORTS) @Override public void 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()); + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeCacheKey.java b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeCacheKey.java index 152528f936..e348e4a854 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeCacheKey.java +++ b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeCacheKey.java @@ -19,7 +19,6 @@ 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.TenantId; import java.io.Serializable; @@ -35,7 +34,7 @@ public class EdgeCacheKey implements Serializable { @Override public String toString() { - return CacheKeyUtil.toString(tenantId, name); + return tenantId + "_" + name; } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewCacheKey.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewCacheKey.java index 6365fb6b45..20e9de06f6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewCacheKey.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewCacheKey.java @@ -18,8 +18,6 @@ package org.thingsboard.server.dao.entityview; 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.EntityId; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; @@ -57,7 +55,13 @@ public class EntityViewCacheKey implements Serializable { @Override public String toString() { - return CacheKeyUtil.toString(tenantId, name, entityId, entityViewId); + if (entityViewId != null) { + return entityViewId.toString(); + } else if (entityId != null) { + return tenantId + "_" + entityId; + } else { + return tenantId + "_n_" + name; + } } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewCacheValue.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewCacheValue.java index ea0f85040d..2d086cf1d6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewCacheValue.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewCacheValue.java @@ -18,11 +18,7 @@ package org.thingsboard.server.dao.entityview; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; -import org.thingsboard.server.cache.CacheKeyUtil; 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; import java.io.Serializable; import java.util.List; 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 index b3acbea6bd..e238c70f2c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageCacheKey.java +++ b/dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageCacheKey.java @@ -19,9 +19,7 @@ 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; @@ -35,7 +33,7 @@ public class OtaPackageCacheKey implements Serializable { @Override public String toString() { - return id.getId().toString(); + return id.toString(); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationCacheKey.java b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationCacheKey.java index b60aa84b9b..f45c8a1344 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationCacheKey.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationCacheKey.java @@ -19,7 +19,6 @@ 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.EntityId; import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.RelationTypeGroup; @@ -46,7 +45,24 @@ public class RelationCacheKey implements Serializable { @Override public String toString() { - return CacheKeyUtil.toString(from, to, typeGroup, type, direction); + StringBuilder sb = new StringBuilder(); + boolean first = add(sb, true, from); + first = add(sb, first, to); + first = add(sb, first, type); + first = add(sb, first, typeGroup); + add(sb, first, direction); + return sb.toString(); + } + + private boolean add(StringBuilder sb, boolean first, Object param) { + if (param != null) { + if (!first) { + sb.append("_"); + } + first = false; + sb.append(param); + } + return first; } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileCacheKey.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileCacheKey.java index 2c921d2f2c..a9bfcbe2ca 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileCacheKey.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileCacheKey.java @@ -47,7 +47,7 @@ public class TenantProfileCacheKey implements Serializable { if (defaultProfile) { return "default"; } else { - return tenantProfileId.getId().toString(); + return tenantProfileId.toString(); } } } diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDaoTest.java index aa99a88ac7..941c2d01ac 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDaoTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDaoTest.java @@ -56,6 +56,8 @@ public class JpaAlarmDaoTest extends AbstractJpaDaoTest { UUID alarm3Id = UUID.fromString("d4b68f45-3e96-11e7-a884-898080180d6b"); int alarmCountBeforeSave = alarmDao.find(TenantId.fromUUID(tenantId)).size(); saveAlarm(alarm1Id, tenantId, originator1Id, "TEST_ALARM"); + //The timestamp of the startTime should be different in order for test to always work + Thread.sleep(1); saveAlarm(alarm2Id, tenantId, originator1Id, "TEST_ALARM"); saveAlarm(alarm3Id, tenantId, originator2Id, "TEST_ALARM"); int alarmCountAfterSave = alarmDao.find(TenantId.fromUUID(tenantId)).size();