From ad97199f04bdc49a7f370d97711f7e06ff520ef6 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Thu, 19 Dec 2024 18:12:00 +0200 Subject: [PATCH] Fix cached entity was updated during inlineImages --- .../controller/AssetProfileController.java | 2 +- .../controller/DeviceProfileController.java | 2 +- .../controller/WidgetsBundleController.java | 2 +- .../impl/AssetProfileExportService.java | 1 - .../impl/DefaultEntityExportService.java | 3 --- .../impl/DeviceProfileExportService.java | 1 - .../impl/WidgetsBundleExportService.java | 1 - .../controller/ImageControllerTest.java | 19 +++++++++++++++++++ .../server/dao/resource/ImageService.java | 2 +- .../server/dao/resource/BaseImageService.java | 10 +++++++++- 10 files changed, 32 insertions(+), 11 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetProfileController.java b/application/src/main/java/org/thingsboard/server/controller/AssetProfileController.java index 4b40cf3854..dfcbc59ca6 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AssetProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AssetProfileController.java @@ -88,7 +88,7 @@ public class AssetProfileController extends BaseController { AssetProfileId assetProfileId = new AssetProfileId(toUUID(strAssetProfileId)); var result = checkAssetProfileId(assetProfileId, Operation.READ); if (inlineImages) { - imageService.inlineImage(result); + result = imageService.inlineImage(result); } return result; } diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java index e7915fc22c..43916e56bf 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java @@ -96,7 +96,7 @@ public class DeviceProfileController extends BaseController { DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId)); var result = checkDeviceProfileId(deviceProfileId, Operation.READ); if (inlineImages) { - imageService.inlineImage(result); + result = imageService.inlineImage(result); } return result; } diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java index 8d39e6c83d..307343f6fb 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java @@ -90,7 +90,7 @@ public class WidgetsBundleController extends BaseController { WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId)); var result = checkWidgetsBundleId(widgetsBundleId, Operation.READ); if (inlineImages) { - imageService.inlineImage(result); + result = imageService.inlineImage(result); } return result; } diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/AssetProfileExportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/AssetProfileExportService.java index 0ff15a0874..5b973bbb46 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/AssetProfileExportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/AssetProfileExportService.java @@ -34,7 +34,6 @@ public class AssetProfileExportService extends BaseEntityExportService ctx, I entityId) throws ThingsboardException { diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DeviceProfileExportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DeviceProfileExportService.java index 60aaf34a3a..69389e7d57 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DeviceProfileExportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DeviceProfileExportService.java @@ -34,7 +34,6 @@ public class DeviceProfileExportService extends BaseEntityExportService fqns = widgetTypeService.findWidgetFqnsByWidgetsBundleId(ctx.getTenantId(), widgetsBundle.getId()); exportData.setFqns(fqns); diff --git a/application/src/test/java/org/thingsboard/server/controller/ImageControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/ImageControllerTest.java index f6cc64fda8..d54810a394 100644 --- a/application/src/test/java/org/thingsboard/server/controller/ImageControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/ImageControllerTest.java @@ -24,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpMethod; import org.springframework.test.context.TestPropertySource; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.ImageDescriptor; import org.thingsboard.server.common.data.ResourceExportData; import org.thingsboard.server.common.data.ResourceSubType; @@ -321,6 +322,24 @@ public class ImageControllerTest extends AbstractControllerTest { assertThat(systemParams.getMaxResourceSize()).isEqualTo(0); } + @Test + public void testInlineImages() throws Exception { + TbResourceInfo imageInfo = uploadImage(HttpMethod.POST, "/api/image", "my_png_image.png", "image/png", PNG_IMAGE); + DeviceProfile deviceProfile = createDeviceProfile("Test"); + deviceProfile.setImage("tb-image;" + imageInfo.getLink()); + deviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); + + DeviceProfile deviceProfileInlined = doGet("/api/deviceProfile/" + deviceProfile.getUuidId() + "?inlineImages=true", DeviceProfile.class); + assertThat(deviceProfileInlined.getImage()).isEqualTo("tb-image:" + + Base64.getEncoder().encodeToString(imageInfo.getResourceKey().getBytes()) + ":" + + Base64.getEncoder().encodeToString(imageInfo.getName().getBytes()) + ":" + + Base64.getEncoder().encodeToString(imageInfo.getResourceSubType().name().getBytes()) + + ";data:image/png;base64," + Base64.getEncoder().encodeToString(PNG_IMAGE)); + + deviceProfile = doGet("/api/deviceProfile/" + deviceProfile.getUuidId(), DeviceProfile.class); + assertThat(deviceProfile.getImage()).isEqualTo("tb-image;" + imageInfo.getLink()); + } + private TbResourceInfo updateImagePublicStatus(String filename, boolean isPublic) throws Exception { return doPut("/api/images/tenant/" + filename + "/public/" + isPublic, "", TbResourceInfo.class); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ImageService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ImageService.java index fc282f6b74..a83b95ae34 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ImageService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ImageService.java @@ -64,7 +64,7 @@ public interface ImageService { boolean updateImagesUsage(WidgetTypeDetails widgetType); - void inlineImage(HasImage entity); + T inlineImage(T entity); Collection getUsedImages(Dashboard dashboard); diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseImageService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseImageService.java index 1cf719d2dc..172b91a32c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseImageService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseImageService.java @@ -27,6 +27,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.cache.CaffeineTbTransactionalCache; import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityType; @@ -526,9 +527,16 @@ public class BaseImageService extends BaseResourceService implements ImageServic } @Override - public void inlineImage(HasImage entity) { + public T inlineImage(T entity) { log.trace("Executing inlineImage [{}] [{}] [{}]", entity.getTenantId(), entity.getClass().getSimpleName(), entity.getName()); + if (StringUtils.isEmpty(entity.getImage())) { + return entity; + } + if (cache instanceof CaffeineTbTransactionalCache) { + entity = JacksonUtil.clone(entity); // cloning the entity to avoid updating the cached one + } entity.setImage(inlineImage(entity.getTenantId(), "image", entity.getImage(), true)); + return entity; } @Override