diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index 95dd2ce7f7..218f0a9153 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -112,6 +112,8 @@ public class ThingsboardInstallService { } else if ("3.0.1-cassandra".equals(upgradeFromVersion)) { log.info("Migrating ThingsBoard latest timeseries data from cassandra to SQL database ..."); latestMigrateService.migrate(); + } else if (upgradeFromVersion.equals("3.6.2-images")) { + installScripts.updateImages(); } else { switch (upgradeFromVersion) { case "1.2.3": //NOSONAR, Need to execute gradual upgrade starting from upgradeFromVersion @@ -279,7 +281,6 @@ public class ThingsboardInstallService { log.info("Updating system data..."); dataUpdateService.upgradeRuleNodes(); systemDataLoaderService.loadSystemWidgets(); -// installScripts.migrateTenantImages(); installScripts.loadSystemLwm2mResources(); } log.info("Upgrade finished successfully!"); diff --git a/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java b/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java index a85ef5e5b1..4947d1a338 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java +++ b/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java @@ -27,12 +27,9 @@ import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.CustomerId; -import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.id.WidgetTypeId; import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationTemplate; import org.thingsboard.server.common.data.page.PageData; -import org.thingsboard.server.common.data.page.PageDataIterable; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; @@ -302,47 +299,12 @@ public class InstallScripts { } } - public void migrateTenantImages() { - var widgetsBundles = new PageDataIterable<>(widgetsBundleService::findAllWidgetsBundles, 100); - for (WidgetsBundle widgetsBundle : widgetsBundles) { - try { - boolean updated = imagesUpdater.updateWidgetsBundle(widgetsBundle); - if (updated) { - widgetsBundleService.saveWidgetsBundle(widgetsBundle); - log.info("[{}][{}][{}] Migrated widgets bundle images", widgetsBundle.getTenantId(), widgetsBundle.getId(), widgetsBundle.getTitle()); - } - } catch (Exception e) { - log.error("[{}][{}][{}] Failed to migrate widgets bundle images", widgetsBundle.getTenantId(), widgetsBundle.getId(), widgetsBundle.getTitle(), e); - } - } - - var widgetTypes = new PageDataIterable<>(widgetTypeService::findAllWidgetTypesIds, 1024); - for (WidgetTypeId widgetTypeId : widgetTypes) { - WidgetTypeDetails widgetTypeDetails = widgetTypeService.findWidgetTypeDetailsById(TenantId.SYS_TENANT_ID, widgetTypeId); - try { - boolean updated = imagesUpdater.updateWidget(widgetTypeDetails); - if (updated) { - widgetTypeService.saveWidgetType(widgetTypeDetails); - log.info("[{}][{}][{}] Migrated widget type images", widgetTypeDetails.getTenantId(), widgetTypeDetails.getId(), widgetTypeDetails.getName()); - } - } catch (Exception e) { - log.error("[{}][{}][{}] Failed to migrate widget type images", widgetTypeDetails.getTenantId(), widgetTypeDetails.getId(), widgetTypeDetails.getName(), e); - } - } - - var dashboards = new PageDataIterable<>(dashboardService::findAllDashboardsIds, 1024); - for (DashboardId dashboardId : dashboards) { - Dashboard dashboard = dashboardService.findDashboardById(TenantId.SYS_TENANT_ID, dashboardId); - try { - boolean updated = imagesUpdater.updateDashboard(dashboard); - if (updated) { - dashboardService.saveDashboard(dashboard); - log.info("[{}][{}][{}] Migrated dashboard images", dashboard.getTenantId(), dashboardId, dashboard.getTitle()); - } - } catch (Exception e) { - log.error("[{}][{}][{}] Failed to migrate dashboard images", dashboard.getTenantId(), dashboardId, dashboard.getTitle(), e); - } - } + public void updateImages() { + imagesUpdater.updateWidgetsBundlesImages(); + imagesUpdater.updateWidgetTypesImages(); + imagesUpdater.updateDashboardsImages(); + imagesUpdater.updateDeviceProfilesImages(); + imagesUpdater.updateAssetProfilesImages(); } public void loadDashboards(TenantId tenantId, CustomerId customerId) throws Exception { diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/ImagesUpdater.java b/application/src/main/java/org/thingsboard/server/service/install/update/ImagesUpdater.java index d657be1122..6bc786d943 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/ImagesUpdater.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/ImagesUpdater.java @@ -15,226 +15,141 @@ */ package org.thingsboard.server.service.install.update; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import lombok.Data; import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Dashboard; -import org.thingsboard.server.common.data.ResourceType; -import org.thingsboard.server.common.data.TbResource; -import org.thingsboard.server.common.data.TbResourceInfo; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.common.data.asset.AssetProfile; +import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.WidgetTypeId; +import org.thingsboard.server.common.data.page.PageDataIterable; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.common.data.widget.WidgetsBundle; +import org.thingsboard.server.dao.asset.AssetProfileDao; +import org.thingsboard.server.dao.dashboard.DashboardDao; +import org.thingsboard.server.dao.device.DeviceProfileDao; import org.thingsboard.server.dao.resource.ImageService; -import org.thingsboard.server.dao.util.ImageUtils; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Base64; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import org.thingsboard.server.dao.widget.WidgetTypeDao; +import org.thingsboard.server.dao.widget.WidgetsBundleDao; @Component -@Slf4j @RequiredArgsConstructor +@Slf4j public class ImagesUpdater { - private final ImageService imageService; + private final WidgetsBundleDao widgetsBundleDao; + private final WidgetTypeDao widgetTypeDao; + private final DashboardDao dashboardDao; + private final DeviceProfileDao deviceProfileDao; + private final AssetProfileDao assetProfileDao; - private static final String IMAGE_NAME_SUFFIX = " - image"; - private static final String BACKGROUND_IMAGE_NAME_SUFFIX = " - background image"; - private static final String BACKGROUND_IMAGE_KEY_SUFFIX = "#background_image"; - private static final String MAP_IMAGE_NAME_SUFFIX = " - map image"; - private static final String MAP_IMAGE_KEY_SUFFIX = "#map_image"; - private static final String MARKER_IMAGE_NAME_SUFFIX = " - marker image "; - private static final String MARKER_IMAGE_KEY_SUFFIX = "#marker_image_"; - - public boolean updateDashboard(Dashboard dashboard) { - String imageKeyPrefix = "dashboard_" + dashboard.getUuidId(); - String image = dashboard.getImage(); - ImageSaveResult result = saveImage(dashboard.getTenantId(), dashboard.getTitle() + IMAGE_NAME_SUFFIX, - imageKeyPrefix + ".image", image, null); - dashboard.setImage(result.getLink()); - boolean updated = result.isUpdated(); - - for (ObjectNode widgetConfig : dashboard.getWidgetsConfig()) { - String fqn; - if (widgetConfig.has("typeFullFqn")) { - fqn = StringUtils.substringAfter(widgetConfig.get("typeFullFqn").asText(), "."); // removing prefix ('system' or 'tenant') - } else { - fqn = widgetConfig.get("bundleAlias").asText() + "." + widgetConfig.get("typeAlias").asText(); - } - String widgetName = widgetConfig.get("config").get("title").asText(); - updated |= updateWidgetConfig(dashboard.getTenantId(), widgetConfig.get("config"), - dashboard.getTitle() + " - " + widgetName + " widget", - imageKeyPrefix + "." + fqn, fqn); - } - return updated; - } - - public boolean updateWidgetsBundle(WidgetsBundle widgetsBundle) { - String bundleName = widgetsBundle.getTitle(); - String bundleAlias = widgetsBundle.getAlias(); - - String image = widgetsBundle.getImage(); - ImageSaveResult result = saveImage(widgetsBundle.getTenantId(), bundleName + IMAGE_NAME_SUFFIX, bundleAlias, image, bundleAlias); - String imageLink = result.getLink(); - widgetsBundle.setImage(imageLink); - - return result.isUpdated(); - } - - public boolean updateWidget(WidgetTypeDetails widgetType) { - String widgetName = widgetType.getName(); - String widgetFqn = widgetType.getFqn(); - boolean updated; - - String previewImage = widgetType.getImage(); - ImageSaveResult result = saveImage(widgetType.getTenantId(), widgetName + IMAGE_NAME_SUFFIX, widgetFqn, previewImage, widgetFqn); - updated = result.isUpdated(); - widgetType.setImage(result.getLink()); - - JsonNode descriptor = widgetType.getDescriptor(); - if (!descriptor.isObject()) { - return updated; - } - JsonNode defaultConfig = JacksonUtil.toJsonNode(descriptor.get("defaultConfig").asText()); - updated |= updateWidgetConfig(widgetType.getTenantId(), defaultConfig, widgetName, widgetFqn, widgetFqn); - ((ObjectNode) descriptor).put("defaultConfig", defaultConfig.toString()); - return updated; - } - - private boolean updateWidgetConfig(TenantId tenantId, JsonNode widgetConfigJson, String imageNamePrefix, String imageKeyPrefix, String widgetFqn) { - boolean updated = false; - ObjectNode widgetSettings = (ObjectNode) widgetConfigJson.get("settings"); - ArrayNode markerImages = (ArrayNode) widgetSettings.get("markerImages"); - if (markerImages != null && !markerImages.isEmpty()) { - for (int i = 0; i < markerImages.size(); i++) { - String imageName = imageNamePrefix + MARKER_IMAGE_NAME_SUFFIX + (i + 1); - String imageKey = imageKeyPrefix + MARKER_IMAGE_KEY_SUFFIX + (i + 1); - ImageSaveResult result = saveImage(tenantId, imageName, imageKey, markerImages.get(i).asText(), widgetFqn); - markerImages.set(i, result.getLink()); - updated |= result.isUpdated(); - } - } - - String mapImage = getText(widgetSettings, "mapImageUrl"); - if (mapImage != null) { - String imageName = imageNamePrefix + MAP_IMAGE_NAME_SUFFIX; - String imageKey = imageKeyPrefix + MAP_IMAGE_KEY_SUFFIX; - ImageSaveResult result = saveImage(tenantId, imageName, imageKey, mapImage, widgetFqn); - widgetSettings.put("mapImageUrl", result.getLink()); - updated |= result.isUpdated(); - } - - String backgroundImage = getText(widgetSettings, "backgroundImageUrl"); - if (backgroundImage != null) { - String imageName = imageNamePrefix + BACKGROUND_IMAGE_NAME_SUFFIX; - String imageKey = imageKeyPrefix + BACKGROUND_IMAGE_KEY_SUFFIX; - ImageSaveResult result = saveImage(tenantId, imageName, imageKey, backgroundImage, widgetFqn); - widgetSettings.put("backgroundImageUrl", result.getLink()); - updated |= result.isUpdated(); - } - - JsonNode backgroundConfigNode = widgetSettings.get("background"); - if (backgroundConfigNode != null && backgroundConfigNode.isObject()) { - ObjectNode backgroundConfig = (ObjectNode) backgroundConfigNode; - if ("image".equals(getText(backgroundConfig, "type"))) { - String imageBase64 = getText(backgroundConfig, "imageBase64"); - if (imageBase64 != null) { - String imageName = imageNamePrefix + BACKGROUND_IMAGE_NAME_SUFFIX; - String imageKey = imageKeyPrefix + BACKGROUND_IMAGE_KEY_SUFFIX; - ImageSaveResult result = saveImage(tenantId, imageName, imageKey, imageBase64, widgetFqn); - backgroundConfig.set("imageBase64", null); - backgroundConfig.put("imageUrl", result.getLink()); - backgroundConfig.put("type", "imageUrl"); - updated |= result.isUpdated(); + public void updateWidgetsBundlesImages() { + log.info("Updating widgets bundles images..."); + var widgetsBundles = new PageDataIterable<>(widgetsBundleDao::findAllWidgetsBundles, 128); + int updatedCount = 0; + int totalCount = 0; + for (WidgetsBundle widgetsBundle : widgetsBundles) { + totalCount++; + try { + boolean updated = imageService.replaceBase64WithImageUrl(widgetsBundle, "bundle"); + if (updated) { + widgetsBundleDao.save(widgetsBundle.getTenantId(), widgetsBundle); + log.debug("[{}][{}][{}] Updated widgets bundle images", widgetsBundle.getTenantId(), widgetsBundle.getId(), widgetsBundle.getTitle()); + updatedCount++; } + } catch (Exception e) { + log.error("[{}][{}][{}] Failed to update widgets bundle images", widgetsBundle.getTenantId(), widgetsBundle.getId(), widgetsBundle.getTitle(), e); } } - return updated; + log.info("Updated {} widgets bundles out of {}", updatedCount, totalCount); } - - private ImageSaveResult saveImage(TenantId tenantId, String name, String key, String data, - String existingImageQuery) { - if (data == null) { - return new ImageSaveResult(null, false); - } - String base64Data = StringUtils.substringAfter(data, "base64,"); - if (base64Data.isEmpty()) { - return new ImageSaveResult(data, false); - } - - String imageMediaType = StringUtils.substringBetween(data, "data:", ";base64"); - String extension = ImageUtils.mediaTypeToFileExtension(imageMediaType); - key += "." + extension; - - byte[] imageData = Base64.getDecoder().decode(base64Data); - String imageLink = saveImage(tenantId, name, key, imageData, imageMediaType, existingImageQuery); - return new ImageSaveResult(imageLink, !imageLink.equals(data)); - } - - @SneakyThrows - private String saveImage(TenantId tenantId, String name, String key, byte[] imageData, String mediaType, - String existingImageQuery) { - TbResourceInfo imageInfo = imageService.getImageInfoByTenantIdAndKey(tenantId, key); - if (imageInfo == null && !tenantId.isSysTenantId() && existingImageQuery != null) { - List similarImages = imageService.findSimilarImagesByTenantIdAndKeyStartingWith(TenantId.SYS_TENANT_ID, imageData, existingImageQuery); - if (similarImages.isEmpty()) { - similarImages = imageService.findSimilarImagesByTenantIdAndKeyStartingWith(tenantId, imageData, existingImageQuery); - } - if (!similarImages.isEmpty()) { - imageInfo = similarImages.get(0); - if (similarImages.size() > 1) { - log.debug("Found more than one image resources for key {}: {}", existingImageQuery, similarImages); + public void updateWidgetTypesImages() { + log.info("Updating widget types images..."); + var widgetTypes = new PageDataIterable<>(widgetTypeDao::findAllWidgetTypesIds, 1024); + int updatedCount = 0; + int totalCount = 0; + for (WidgetTypeId widgetTypeId : widgetTypes) { + totalCount++; + WidgetTypeDetails widgetTypeDetails = widgetTypeDao.findById(TenantId.SYS_TENANT_ID, widgetTypeId.getId()); + try { + boolean updated = imageService.replaceBase64WithImageUrl(widgetTypeDetails); + if (updated) { + widgetTypeDao.save(widgetTypeDetails.getTenantId(), widgetTypeDetails); + log.debug("[{}][{}][{}] Updated widget type images", widgetTypeDetails.getTenantId(), widgetTypeDetails.getId(), widgetTypeDetails.getName()); + updatedCount++; } - String link = imageInfo.getLink(); - log.info("[{}] Using image {} for {}", tenantId, link, key); - return link; + } catch (Exception e) { + log.error("[{}][{}][{}] Failed to update widget type images", widgetTypeDetails.getTenantId(), widgetTypeDetails.getId(), widgetTypeDetails.getName(), e); } } - TbResource image; - if (imageInfo == null) { - image = new TbResource(); - image.setTenantId(tenantId); - image.setResourceType(ResourceType.IMAGE); - image.setResourceKey(key); - } else if (tenantId.isSysTenantId()) { - image = new TbResource(imageInfo); - } else { - return imageInfo.getLink(); + log.info("Updated {} widget types out of {}", updatedCount, totalCount); + } + + public void updateDashboardsImages() { + log.info("Updating dashboards images..."); + var dashboards = new PageDataIterable<>(dashboardDao::findAllIds, 1024); + int updatedCount = 0; + int totalCount = 0; + for (DashboardId dashboardId : dashboards) { + totalCount++; + Dashboard dashboard = dashboardDao.findById(TenantId.SYS_TENANT_ID, dashboardId.getId()); + try { + boolean updated = imageService.replaceBase64WithImageUrl(dashboard); + if (updated) { + dashboardDao.save(dashboard.getTenantId(), dashboard); + log.info("[{}][{}][{}] Updated dashboard images", dashboard.getTenantId(), dashboardId, dashboard.getTitle()); + updatedCount++; + } + } catch (Exception e) { + log.error("[{}][{}][{}] Failed to update dashboard images", dashboard.getTenantId(), dashboardId, dashboard.getTitle(), e); + } } - image.setTitle(name); - image.setFileName(key); - image.setDescriptor(JacksonUtil.newObjectNode() - .put("mediaType", mediaType)); - image.setData(imageData); - - TbResourceInfo savedImage = imageService.saveImage(image); - log.info("[{}] {} image '{}' ({})", tenantId, imageInfo == null ? "Created" : "Updated", - image.getTitle(), image.getResourceKey()); - return savedImage.getLink(); + log.info("Updated {} dashboards out of {}", updatedCount, totalCount); } - private String getText(JsonNode jsonNode, String field) { - return Optional.ofNullable(jsonNode.get(field)) - .filter(JsonNode::isTextual) - .map(JsonNode::asText).orElse(null); + public void updateDeviceProfilesImages() { + log.info("Updating device profiles images..."); + var deviceProfiles = new PageDataIterable<>(deviceProfileDao::findAll, 256); + int updatedCount = 0; + int totalCount = 0; + for (DeviceProfile deviceProfile : deviceProfiles) { + totalCount++; + try { + boolean updated = imageService.replaceBase64WithImageUrl(deviceProfile, "device profile"); + if (updated) { + deviceProfileDao.save(deviceProfile.getTenantId(), deviceProfile); + log.debug("[{}][{}][{}] Updated device profile images", deviceProfile.getTenantId(), deviceProfile.getId(), deviceProfile.getName()); + updatedCount++; + } + } catch (Exception e) { + log.error("[{}][{}][{}] Failed to update device profile images", deviceProfile.getTenantId(), deviceProfile.getId(), deviceProfile.getName(), e); + } + } + log.info("Updated {} device profiles out of {}", updatedCount, totalCount); } - @Data - public static class ImageSaveResult { - private final String link; - private final boolean updated; + public void updateAssetProfilesImages() { + log.info("Updating asset profiles images..."); + var assetProfiles = new PageDataIterable<>(assetProfileDao::findAll, 256); + int updatedCount = 0; + int totalCount = 0; + for (AssetProfile assetProfile : assetProfiles) { + totalCount++; + try { + boolean updated = imageService.replaceBase64WithImageUrl(assetProfile, "asset profile"); + if (updated) { + assetProfileDao.save(assetProfile.getTenantId(), assetProfile); + log.debug("[{}][{}][{}] Updated asset profile images", assetProfile.getTenantId(), assetProfile.getId(), assetProfile.getName()); + updatedCount++; + } + } catch (Exception e) { + log.error("[{}][{}][{}] Failed to update asset profile images", assetProfile.getTenantId(), assetProfile.getId(), assetProfile.getName(), e); + } + } + log.info("Updated {} asset profiles out of {}", updatedCount, totalCount); } } diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/SystemImagesMigrator.java b/application/src/main/java/org/thingsboard/server/service/install/update/SystemImagesMigrator.java deleted file mode 100644 index a1f93d505a..0000000000 --- a/application/src/main/java/org/thingsboard/server/service/install/update/SystemImagesMigrator.java +++ /dev/null @@ -1,145 +0,0 @@ -/** - * Copyright © 2016-2023 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.service.install.update; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.springframework.util.Base64Utils; -import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.server.dao.util.ImageUtils; - -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Optional; - -@Slf4j -public class SystemImagesMigrator { - - private static final Path dataDir = Path.of( - "/home/*/thingsboard-ce/application/src/main/data" - ); - private static final Path imagesDir = dataDir.resolve("images"); - private static final Path widgetBundlesDir = dataDir.resolve("json").resolve("system").resolve("widget_bundles"); - private static final Path widgetTypesDir = dataDir.resolve("json").resolve("system").resolve("widget_types"); - private static final Path demoDashboardsDir = dataDir.resolve("json").resolve("demo").resolve("dashboards"); - - public static void main(String[] args) throws Exception { - Files.list(widgetTypesDir).forEach(file -> { - ObjectNode widgetTypeJson = (ObjectNode) JacksonUtil.toJsonNode(file.toFile()); - updateWidget(widgetTypeJson); - saveJson(file, widgetTypeJson); - }); - - Files.list(widgetBundlesDir).forEach(file -> { - JsonNode widgetsBundleDescriptorJson = JacksonUtil.toJsonNode(file.toFile()); - ObjectNode widgetsBundleJson = (ObjectNode) widgetsBundleDescriptorJson.get("widgetsBundle"); - updateWidgetsBundle(widgetsBundleJson); - saveJson(file, widgetsBundleDescriptorJson); - }); - - Files.list(demoDashboardsDir).forEach(file -> { - ObjectNode dashboardJson = (ObjectNode) JacksonUtil.toJsonNode(file.toFile()); - updateDashboard(dashboardJson); - saveJson(file, dashboardJson); - }); - } - - public static void updateWidgetsBundle(ObjectNode widgetsBundleJson) { - String imageLink = getText(widgetsBundleJson, "image"); - widgetsBundleJson.put("image", inlineImage(imageLink, "widget_bundles")); - } - - public static void updateWidget(ObjectNode widgetJson) { - String previewImageLink = widgetJson.get("image").asText(); - widgetJson.put("image", inlineImage(previewImageLink, "widgets")); - - ObjectNode descriptor = (ObjectNode) widgetJson.get("descriptor"); - JsonNode defaultConfig = JacksonUtil.toJsonNode(descriptor.get("defaultConfig").asText()); - updateWidgetConfig(defaultConfig, "widgets"); - descriptor.put("defaultConfig", defaultConfig.toString()); - } - - public static void updateDashboard(ObjectNode dashboardJson) { - String image = getText(dashboardJson, "image"); - dashboardJson.put("image", inlineImage(image, "dashboards")); - - dashboardJson.get("configuration").get("widgets").elements().forEachRemaining(widgetConfig -> { - updateWidgetConfig(widgetConfig.get("config"), "dashboards"); - }); - } - - private static void updateWidgetConfig(JsonNode widgetConfigJson, String directory) { - ObjectNode widgetSettings = (ObjectNode) widgetConfigJson.get("settings"); - ArrayNode markerImages = (ArrayNode) widgetSettings.get("markerImages"); - if (markerImages != null && !markerImages.isEmpty()) { - for (int i = 0; i < markerImages.size(); i++) { - markerImages.set(i, inlineImage(markerImages.get(i).asText(), directory)); - } - } - - String mapImage = getText(widgetSettings, "mapImageUrl"); - if (mapImage != null) { - widgetSettings.put("mapImageUrl", inlineImage(mapImage, directory)); - } - - String backgroundImage = getText(widgetSettings, "backgroundImageUrl"); - if (backgroundImage != null) { - widgetSettings.put("backgroundImageUrl", inlineImage(backgroundImage, directory)); - } - - JsonNode backgroundConfigNode = widgetSettings.get("background"); - if (backgroundConfigNode != null && backgroundConfigNode.isObject()) { - ObjectNode backgroundConfig = (ObjectNode) backgroundConfigNode; - if ("imageUrl".equals(getText(backgroundConfig, "type"))) { - String imageLink = getText(backgroundConfig, "imageUrl"); - if (imageLink != null && imageLink.startsWith("/api/images")) { - backgroundConfig.put("imageBase64", inlineImage(imageLink, directory)); - backgroundConfig.set("imageUrl", null); - backgroundConfig.put("type", "image"); - } - } - } - } - - @SneakyThrows - private static String inlineImage(String url, String subDir) { - if (url != null && url.startsWith("/api/images")) { - String imageKey = StringUtils.substringAfterLast(url, "/"); - Path file = imagesDir.resolve(subDir).resolve(imageKey); - String mediaType = ImageUtils.fileExtensionToMediaType(StringUtils.substringAfterLast(imageKey, ".")); - return "data:" + mediaType + ";base64," + Base64Utils.encodeToString(Files.readAllBytes(file)); - } else { - return url; - } - } - - private static String getText(JsonNode jsonNode, String field) { - return Optional.ofNullable(jsonNode.get(field)) - .filter(JsonNode::isTextual) - .map(JsonNode::asText).orElse(null); - } - - @SneakyThrows - private static void saveJson(Path file, JsonNode json) { - Files.write(file, JacksonUtil.toPrettyString(json).getBytes(StandardCharsets.UTF_8)); - } - -} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java index a3285a8ecf..d94256bb99 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java @@ -29,7 +29,7 @@ import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.List; public interface DashboardService extends EntityDaoService { - + Dashboard findDashboardById(TenantId tenantId, DashboardId dashboardId); ListenableFuture findDashboardByIdAsync(TenantId tenantId, DashboardId dashboardId); @@ -74,6 +74,4 @@ public interface DashboardService extends EntityDaoService { List findTenantDashboardsByTitle(TenantId tenantId, String title); - PageData findAllDashboardsIds(PageLink pageLink); - } 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 6d561a289d..cc192436e7 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 @@ -16,7 +16,6 @@ package org.thingsboard.server.dao.resource; import org.thingsboard.server.common.data.Dashboard; -import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.HasImage; import org.thingsboard.server.common.data.TbImageDeleteResult; import org.thingsboard.server.common.data.TbResource; @@ -25,11 +24,8 @@ import org.thingsboard.server.common.data.id.TbResourceId; 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.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; -import java.util.List; - public interface ImageService { TbResourceInfo saveImage(TbResource image); @@ -48,11 +44,9 @@ public interface ImageService { TbImageDeleteResult deleteImage(TbResourceInfo imageInfo, boolean force); - List findSimilarImagesByTenantIdAndKeyStartingWith(TenantId tenantId, byte[] data, String imageKeyStartingWith); - TbResourceInfo findImageByTenantIdAndEtag(TenantId tenantId, String etag); - boolean replaceBase64WithImageUrl(HasImage hasImage, String title, String type); + boolean replaceBase64WithImageUrl(HasImage entity, String type); boolean replaceBase64WithImageUrl(Dashboard dashboard); boolean replaceBase64WithImageUrl(WidgetTypeDetails widgetType); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java index 4cfc7f5963..b4cda2d733 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java @@ -27,7 +27,6 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.List; -import java.util.Set; public interface ResourceService extends EntityDaoService { @@ -55,8 +54,6 @@ public interface ResourceService extends EntityDaoService { PageData findTenantResourcesByResourceTypeAndPageLink(TenantId tenantId, ResourceType lwm2mModel, PageLink pageLink); - Set findResourceKeysByTenantIdResourceTypeAndKeyPrefix(TenantId tenantId, ResourceType resourceType, String key); - void deleteResource(TenantId tenantId, TbResourceId resourceId); void deleteResource(TenantId tenantId, TbResourceId resourceId, boolean force); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java index 6db79821b9..d8df5d61a3 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java @@ -62,6 +62,4 @@ public interface WidgetTypeService extends EntityDaoService { void deleteWidgetTypesByTenantId(TenantId tenantId); - PageData findAllWidgetTypesIds(PageLink pageLink); - } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleService.java index 224cb9511f..a836fb893d 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleService.java @@ -46,8 +46,6 @@ public interface WidgetsBundleService extends EntityDaoService { List findAllTenantWidgetsBundlesByTenantId(TenantId tenantId); - PageData findAllWidgetsBundles(PageLink pageLink); - void deleteWidgetsBundlesByTenantId(TenantId tenantId); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/HasImage.java b/common/data/src/main/java/org/thingsboard/server/common/data/HasImage.java index 6acaa992c3..38b01e1005 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/HasImage.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/HasImage.java @@ -15,7 +15,7 @@ */ package org.thingsboard.server.common.data; -public interface HasImage extends HasTenantId { +public interface HasImage extends HasTenantId, HasName { String getImage(); diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileDao.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileDao.java index bffe9e86e9..14e023edcd 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileDao.java @@ -21,7 +21,6 @@ import org.thingsboard.server.common.data.id.AssetProfileId; 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.data.widget.WidgetsBundle; import org.thingsboard.server.dao.Dao; import org.thingsboard.server.dao.ExportableEntityDao; import org.thingsboard.server.dao.ImageContainerDao; @@ -45,4 +44,7 @@ public interface AssetProfileDao extends Dao, ExportableEntityDao< AssetProfileInfo findDefaultAssetProfileInfo(TenantId tenantId); AssetProfile findByName(TenantId tenantId, String profileName); + + PageData findAll(PageLink pageLink); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java index 884d30e317..86cafcd10b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java @@ -145,7 +145,7 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService findAllDashboardsIds(PageLink pageLink) { - return dashboardDao.findAllIds(pageLink); - } - private final PaginatedRemover tenantDashboardsRemover = new PaginatedRemover<>() { @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileDao.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileDao.java index d3a13d82bf..c5ca8c054d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileDao.java @@ -17,7 +17,6 @@ package org.thingsboard.server.dao.device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfileInfo; -import org.thingsboard.server.common.data.asset.AssetProfileInfo; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; @@ -47,4 +46,7 @@ public interface DeviceProfileDao extends Dao, ExportableEntityDa DeviceProfile findByProvisionDeviceKey(String provisionDeviceKey); DeviceProfile findByName(TenantId tenantId, String profileName); + + PageData findAll(PageLink pageLink); + } 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 529d926a12..847811cd4f 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 @@ -182,7 +182,7 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService existing = resourceInfoDao.findKeysByTenantIdAndResourceTypeAndResourceKeyPrefix( + tenantId, ResourceType.IMAGE, basename ); - int maxImageIdx = resourceInfoDao.findKeysByTenantIdAndResourceTypeAndResourceKeyStartingWith( - tenantId, ResourceType.IMAGE, basename + "_").stream() - .map(key -> RegexUtils.getMatch(key, similarImagesPattern, 1)) - .filter(Objects::nonNull).mapToInt(Integer::parseInt) - .max().orElse(0); - String uniqueKey = basename + "_" + (maxImageIdx + 1); - if (!extension.isEmpty()) { - uniqueKey += "." + extension; + String resourceKey = filename; + int idx = 1; + while (existing.contains(resourceKey)) { + resourceKey = basename + "_(" + idx + ")." + extension; + idx++; } - return uniqueKey; + return resourceKey; } @Override @@ -259,47 +254,57 @@ public class BaseImageService extends BaseResourceService implements ImageServic return result.success(success).build(); } - @Override - public List findSimilarImagesByTenantIdAndKeyStartingWith(TenantId tenantId, byte[] data, String imageKeyStartingWith) { - String etag = calculateEtag(data); - return resourceInfoDao.findByTenantIdAndEtagAndKeyStartingWith(tenantId, etag, imageKeyStartingWith); - } - @Override public TbResourceInfo findImageByTenantIdAndEtag(TenantId tenantId, String etag) { return resourceInfoDao.findByTenantIdAndEtag(tenantId, ResourceType.IMAGE, etag); } @Override - public boolean replaceBase64WithImageUrl(HasImage entity, String title, String type) { - entity.setImage(base64ToImageUrl(entity.getTenantId(), "\"" + title + "\" " + type + " image", entity.getImage())); - return true; //TODO: should return true only if something is changed. + public boolean replaceBase64WithImageUrl(HasImage entity, String type) { + String imageName = "\"" + entity.getName() + "\" "; + if (entity.getTenantId() == null || entity.getTenantId().isSysTenantId()) { + imageName += "system "; + } + imageName = imageName + type + " image"; + + UpdateResult result = base64ToImageUrl(entity.getTenantId(), imageName, entity.getImage()); + entity.setImage(result.getValue()); + return result.isUpdated(); } @Override public boolean replaceBase64WithImageUrl(WidgetTypeDetails entity) { - String prefix = "\"" + entity.getName() + "\" widget"; // TODO: "system widget" if SYS TENANT ID; - entity.setImage(base64ToImageUrl(entity.getTenantId(), prefix + " image", entity.getImage())); + String prefix = "\"" + entity.getName() + "\" "; + if (entity.getTenantId() == null || entity.getTenantId().isSysTenantId()) { + prefix += "system "; + } + prefix += "widget"; + UpdateResult result = base64ToImageUrl(entity.getTenantId(), prefix + " image", entity.getImage()); + entity.setImage(result.getValue()); + boolean updated = result.isUpdated(); if (entity.getDescriptor().isObject()) { ObjectNode descriptor = (ObjectNode) entity.getDescriptor(); JsonNode defaultConfig = JacksonUtil.toJsonNode(descriptor.get("defaultConfig").asText()); - base64ToImageUrlUsingMapping(entity.getTenantId(), WIDGET_TYPE_BASE64_MAPPING, Collections.singletonMap("prefix", prefix), defaultConfig); + updated |= base64ToImageUrlUsingMapping(entity.getTenantId(), WIDGET_TYPE_BASE64_MAPPING, Collections.singletonMap("prefix", prefix), defaultConfig); descriptor.put("defaultConfig", defaultConfig.toString()); } - base64ToImageUrlRecursively(entity.getTenantId(), prefix, entity.getDescriptor()); - return true; //TODO: should return true only if something is changed. + updated |= base64ToImageUrlRecursively(entity.getTenantId(), prefix, entity.getDescriptor()); + return updated; } @Override public boolean replaceBase64WithImageUrl(Dashboard entity) { String prefix = "\"" + entity.getTitle() + "\" dashboard"; - entity.setImage(base64ToImageUrl(entity.getTenantId(), prefix + " image", entity.getImage())); - base64ToImageUrlUsingMapping(entity.getTenantId(), DASHBOARD_BASE64_MAPPING, Collections.singletonMap("prefix", prefix), entity.getConfiguration()); - base64ToImageUrlRecursively(entity.getTenantId(), prefix, entity.getConfiguration()); - return true; //TODO: should return true only if something is changed. + var result = base64ToImageUrl(entity.getTenantId(), prefix + " image", entity.getImage()); + boolean updated = result.isUpdated(); + entity.setImage(result.getValue()); + updated |= base64ToImageUrlUsingMapping(entity.getTenantId(), DASHBOARD_BASE64_MAPPING, Collections.singletonMap("prefix", prefix), entity.getConfiguration()); + updated |= base64ToImageUrlRecursively(entity.getTenantId(), prefix, entity.getConfiguration()); + return updated; } - private void base64ToImageUrlUsingMapping(TenantId tenantId, Map mapping, Map templateParams, JsonNode configuration) { + private boolean base64ToImageUrlUsingMapping(TenantId tenantId, Map mapping, Map templateParams, JsonNode configuration) { + boolean updated = false; for (var entry : mapping.entrySet()) { String expression = entry.getValue(); Queue tasks = new LinkedList<>(); @@ -330,8 +335,8 @@ public class BaseImageService extends BaseResourceService implements ImageServic String variableName = null; String variableValue = null; if (token.contains("[$")) { - variableName = org.apache.commons.lang3.StringUtils.substringBetween(token, "[$", "]"); - token = org.apache.commons.lang3.StringUtils.substringBefore(token, "[$"); + variableName = StringUtils.substringBetween(token, "[$", "]"); + token = StringUtils.substringBefore(token, "[$"); } if (node.has(token)) { JsonNode value = node.get(token); @@ -344,16 +349,20 @@ public class BaseImageService extends BaseResourceService implements ImageServic name = name.replace("$" + replacements.getKey(), replacements.getValue()); } if (node.isObject() && value.isTextual()) { - ((ObjectNode) node).put(token, base64ToImageUrl(tenantId, name, value.asText())); + var result = base64ToImageUrl(tenantId, name, value.asText()); + ((ObjectNode) node).put(token, result.getValue()); + updated |= result.isUpdated(); } else if (value.isArray()) { ArrayNode array = (ArrayNode) value; for (int i = 0; i < array.size(); i++) { String arrayElementName = name.replace("$index", Integer.toString(i)); - array.set(i, base64ToImageUrl(tenantId, arrayElementName, array.get(i).asText())); + UpdateResult result = base64ToImageUrl(tenantId, arrayElementName, array.get(i).asText()); + array.set(i, result.getValue()); + updated |= result.isUpdated(); } } } else { - if (org.thingsboard.server.common.data.StringUtils.isNotEmpty(variableName) && org.thingsboard.server.common.data.StringUtils.isNotEmpty(variableValue)) { + if (StringUtils.isNotEmpty(variableName) && StringUtils.isNotEmpty(variableValue)) { tasks.add(task.next(value, variableName, variableValue)); } else { tasks.add(task.next(value)); @@ -363,17 +372,18 @@ public class BaseImageService extends BaseResourceService implements ImageServic } } } + return updated; } - private String base64ToImageUrl(TenantId tenantId, String name, String data) { + private UpdateResult base64ToImageUrl(TenantId tenantId, String name, String data) { return base64ToImageUrl(tenantId, name, data, false); } private static final Pattern TB_IMAGE_METADATA_PATTERN = Pattern.compile("^tb-image:(.*):(.*);data:(.*);.*"); - private String base64ToImageUrl(TenantId tenantId, String name, String data, boolean strict) { + private UpdateResult base64ToImageUrl(TenantId tenantId, String name, String data, boolean strict) { if (StringUtils.isBlank(data)) { - return data; + return UpdateResult.of(false, data); } var matcher = TB_IMAGE_METADATA_PATTERN.matcher(data); boolean matches = matcher.matches(); @@ -385,67 +395,58 @@ public class BaseImageService extends BaseResourceService implements ImageServic mdResourceName = new String(Base64Utils.decodeFromString(matcher.group(2)), StandardCharsets.UTF_8); mdMediaType = matcher.group(3); } else if (data.startsWith(DataConstants.TB_IMAGE_PREFIX + "data:image/") || (!strict && data.startsWith("data:image/"))) { - mdMediaType = org.apache.commons.lang3.StringUtils.substringBetween(data, "data:", ";base64"); + mdMediaType = StringUtils.substringBetween(data, "data:", ";base64"); } else { - return data; + return UpdateResult.of(false, data); } - String base64Data = org.apache.commons.lang3.StringUtils.substringAfter(data, "base64,"); + String base64Data = StringUtils.substringAfter(data, "base64,"); String extension = ImageUtils.mediaTypeToFileExtension(mdMediaType); byte[] imageData = Base64.getDecoder().decode(base64Data); - String etag = Hashing.sha256().hashBytes(imageData).toString(); + String etag = calculateEtag(imageData); var imageInfo = findImageByTenantIdAndEtag(tenantId, etag); if (imageInfo == null) { TbResource image = new TbResource(); image.setTenantId(tenantId); image.setResourceType(ResourceType.IMAGE); - if (StringUtils.isBlank(mdResourceName)) { mdResourceName = name; } + image.setTitle(mdResourceName); String fileName; if (StringUtils.isBlank(mdResourceKey)) { fileName = mdResourceName.toLowerCase() - //TODO: improve to list all the special characters via regexp or similar - .replace("'", "") - .replace("\"", "") - .replace(" ", "_") - .replace("/", "_"); - mdResourceKey = fileName + "." + extension; + .replace("'", "").replace("\"", "") + .replace(" ", "_").replace("/", "_") + + "." + extension; } else { - fileName = mdResourceKey.split("\\.")[0]; + fileName = mdResourceKey; } - - Set existingKeys = findResourceKeysByTenantIdResourceTypeAndKeyPrefix(tenantId, ResourceType.IMAGE, mdResourceKey); - int idx = 1; - while (existingKeys.contains(mdResourceKey)) { - mdResourceKey = fileName + "_(" + idx + ")." + extension; - idx++; - } - image.setResourceKey(mdResourceKey); - image.setTitle(mdResourceName); - image.setFileName(mdResourceKey); + image.setFileName(fileName); image.setDescriptor(JacksonUtil.newObjectNode().put("mediaType", mdMediaType)); image.setData(imageData); imageInfo = saveImage(image); } - return DataConstants.TB_IMAGE_PREFIX + imageInfo.getLink(); + return UpdateResult.of(true, DataConstants.TB_IMAGE_PREFIX + imageInfo.getLink()); } - private void base64ToImageUrlRecursively(TenantId tenantId, String title, JsonNode root) { + private boolean base64ToImageUrlRecursively(TenantId tenantId, String title, JsonNode root) { + boolean updated = false; Queue tasks = new LinkedList<>(); tasks.add(new JsonNodeProcessingTask(title, root)); while (!tasks.isEmpty()) { JsonNodeProcessingTask task = tasks.poll(); JsonNode node = task.getNode(); - String currentPath = org.thingsboard.server.common.data.StringUtils.isBlank(task.getPath()) ? "" : (task.getPath() + " "); + String currentPath = StringUtils.isBlank(task.getPath()) ? "" : (task.getPath() + " "); if (node.isObject()) { ObjectNode on = (ObjectNode) node; for (Iterator it = on.fieldNames(); it.hasNext(); ) { String childName = it.next(); JsonNode childValue = on.get(childName); if (childValue.isTextual()) { - on.put(childName, base64ToImageUrl(tenantId, currentPath + childName, childValue.asText(), true)); + UpdateResult result = base64ToImageUrl(tenantId, currentPath + childName, childValue.asText(), true); + on.put(childName, result.getValue()); + updated |= result.isUpdated(); } else if (childValue.isObject() || childValue.isArray()) { tasks.add(new JsonNodeProcessingTask(currentPath + childName, childValue)); } @@ -461,6 +462,7 @@ public class BaseImageService extends BaseResourceService implements ImageServic } } } + return updated; } @Override @@ -486,7 +488,7 @@ public class BaseImageService extends BaseResourceService implements ImageServic while (!tasks.isEmpty()) { JsonNodeProcessingTask task = tasks.poll(); JsonNode node = task.getNode(); - String currentPath = org.thingsboard.server.common.data.StringUtils.isBlank(task.getPath()) ? "" : (task.getPath() + "."); + String currentPath = StringUtils.isBlank(task.getPath()) ? "" : (task.getPath() + "."); if (node.isObject()) { ObjectNode on = (ObjectNode) node; for (Iterator it = on.fieldNames(); it.hasNext(); ) { @@ -536,7 +538,7 @@ public class BaseImageService extends BaseResourceService implements ImageServic } private ImageCacheKey getKeyFromUrl(TenantId tenantId, String url) { - if (org.thingsboard.server.common.data.StringUtils.isBlank(url)) { + if (StringUtils.isBlank(url)) { return null; } TenantId imageTenantId = null; @@ -555,4 +557,10 @@ public class BaseImageService extends BaseResourceService implements ImageServic } return null; } + + @Data(staticConstructor = "of") + private static class UpdateResult { + private final boolean updated; + private final String value; + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java index b9aa0b100d..d935409afb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java @@ -44,10 +44,8 @@ import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.dao.service.validator.ResourceDataValidator; -import java.util.HashSet; import java.util.List; import java.util.Optional; -import java.util.Set; import static org.thingsboard.server.dao.device.DeviceServiceImpl.INCORRECT_TENANT_ID; import static org.thingsboard.server.dao.service.Validator.validateId; @@ -199,13 +197,6 @@ public class BaseResourceService extends AbstractCachedEntityService findResourceKeysByTenantIdResourceTypeAndKeyPrefix(TenantId tenantId, ResourceType resourceType, String key) { - log.trace("Executing findResourceKeysByTenantIdAndPrefix [{}][{}]", tenantId, key); - validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - return resourceDao.findResourceKeysByTenantIdResourceTypeAndKeyPrefix(tenantId, resourceType, key); - } - @Override public void deleteResourcesByTenantId(TenantId tenantId) { log.trace("Executing deleteResourcesByTenantId, tenantId [{}]", tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/TbResourceDao.java b/dao/src/main/java/org/thingsboard/server/dao/resource/TbResourceDao.java index f2ca16c313..8d0ce7fb35 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/TbResourceDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/TbResourceDao.java @@ -26,7 +26,6 @@ import org.thingsboard.server.dao.ExportableEntityDao; import org.thingsboard.server.dao.TenantEntityWithDataDao; import java.util.List; -import java.util.Set; public interface TbResourceDao extends Dao, TenantEntityWithDataDao, ExportableEntityDao { @@ -47,5 +46,4 @@ public interface TbResourceDao extends Dao, TenantEntityWithDataDao, byte[] getResourcePreview(TenantId tenantId, TbResourceId resourceId); - Set findResourceKeysByTenantIdResourceTypeAndKeyPrefix(TenantId tenantId, ResourceType resourceType, String keyPrefix); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/TbResourceInfoDao.java b/dao/src/main/java/org/thingsboard/server/dao/resource/TbResourceInfoDao.java index 237c7f44dd..6cfc7eaa94 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/TbResourceInfoDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/TbResourceInfoDao.java @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.Dao; import java.util.List; +import java.util.Set; public interface TbResourceInfoDao extends Dao { @@ -35,7 +36,7 @@ public interface TbResourceInfoDao extends Dao { boolean existsByTenantIdAndResourceTypeAndResourceKey(TenantId tenantId, ResourceType resourceType, String resourceKey); - List findKeysByTenantIdAndResourceTypeAndResourceKeyStartingWith(TenantId tenantId, ResourceType resourceType, String resourceKeyQuery); + Set findKeysByTenantIdAndResourceTypeAndResourceKeyPrefix(TenantId tenantId, ResourceType resourceType, String prefix); List findByTenantIdAndEtagAndKeyStartingWith(TenantId tenantId, String etag, String query); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetProfileDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetProfileDao.java index 4d6c8c0406..98bdca1cc9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetProfileDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetProfileDao.java @@ -33,7 +33,6 @@ import org.thingsboard.server.dao.model.sql.AssetProfileEntity; import org.thingsboard.server.dao.sql.JpaAbstractDao; import java.util.List; -import java.util.Objects; import java.util.Optional; import java.util.UUID; @@ -99,6 +98,11 @@ public class JpaAssetProfileDao extends JpaAbstractDao findAll(PageLink pageLink) { + return DaoUtil.toPageData(assetProfileRepository.findAll(DaoUtil.toPageable(pageLink))); + } + @Override public AssetProfile findByTenantIdAndExternalId(UUID tenantId, UUID externalId) { return DaoUtil.getData(assetProfileRepository.findByTenantIdAndExternalId(tenantId, externalId)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java index 201545d164..33d41b892c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java @@ -25,7 +25,6 @@ import org.thingsboard.server.common.data.DeviceProfileInfo; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; -import org.thingsboard.server.common.data.asset.AssetProfileInfo; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; @@ -37,7 +36,6 @@ import org.thingsboard.server.dao.sql.JpaAbstractDao; import org.thingsboard.server.dao.util.SqlDao; import java.util.List; -import java.util.Objects; import java.util.Optional; import java.util.UUID; @@ -118,6 +116,11 @@ public class JpaDeviceProfileDao extends JpaAbstractDao findAll(PageLink pageLink) { + return DaoUtil.toPageData(deviceProfileRepository.findAll(DaoUtil.toPageable(pageLink))); + } + @Override public DeviceProfile findByTenantIdAndExternalId(UUID tenantId, UUID externalId) { return DaoUtil.getData(deviceProfileRepository.findByTenantIdAndExternalId(tenantId, externalId)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceDao.java index 08cf3dd860..370b21a90e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceDao.java @@ -31,9 +31,7 @@ import org.thingsboard.server.dao.resource.TbResourceDao; import org.thingsboard.server.dao.sql.JpaAbstractDao; import org.thingsboard.server.dao.util.SqlDao; -import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.UUID; @Slf4j @@ -127,11 +125,6 @@ public class JpaTbResourceDao extends JpaAbstractDao findResourceKeysByTenantIdResourceTypeAndKeyPrefix(TenantId tenantId, ResourceType resourceType, String keyPrefix) { - return new HashSet<>(resourceRepository.findResourceKeys(tenantId.getId(), resourceType.name(), keyPrefix + "%")); - } - @Override public TbResourceId getExternalIdByInternal(TbResourceId internalId) { return DaoUtil.toEntityId(resourceRepository.getExternalIdByInternal(internalId.getId()), TbResourceId::new); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceInfoDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceInfoDao.java index 71696dd2f4..32934e8854 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceInfoDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceInfoDao.java @@ -17,7 +17,6 @@ package org.thingsboard.server.dao.sql.resource; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.PageRequest; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.ResourceType; @@ -97,8 +96,8 @@ public class JpaTbResourceInfoDao extends JpaAbstractDao findKeysByTenantIdAndResourceTypeAndResourceKeyStartingWith(TenantId tenantId, ResourceType resourceType, String resourceKeyQuery) { - return resourceInfoRepository.findKeysByTenantIdAndResourceTypeAndResourceKeyStartingWith(tenantId.getId(), resourceType.name(), resourceKeyQuery); + public Set findKeysByTenantIdAndResourceTypeAndResourceKeyPrefix(TenantId tenantId, ResourceType resourceType, String prefix) { + return resourceInfoRepository.findKeysByTenantIdAndResourceTypeAndResourceKeyStartingWith(tenantId.getId(), resourceType.name(), prefix); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/resource/TbResourceInfoRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/resource/TbResourceInfoRepository.java index 4ebdd1f10c..f59766d5e5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/resource/TbResourceInfoRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/resource/TbResourceInfoRepository.java @@ -23,6 +23,7 @@ import org.springframework.data.repository.query.Param; import org.thingsboard.server.dao.model.sql.TbResourceInfoEntity; import java.util.List; +import java.util.Set; import java.util.UUID; public interface TbResourceInfoRepository extends JpaRepository { @@ -57,10 +58,10 @@ public interface TbResourceInfoRepository extends JpaRepository findKeysByTenantIdAndResourceTypeAndResourceKeyStartingWith(@Param("tenantId") UUID tenantId, - @Param("resourceType") String resourceType, - @Param("resourceKeyStartsWith") String resourceKeyStartsWith); + "AND starts_with(r.resource_key, :prefix)", nativeQuery = true) + Set findKeysByTenantIdAndResourceTypeAndResourceKeyStartingWith(@Param("tenantId") UUID tenantId, + @Param("resourceType") String resourceType, + @Param("prefix") String prefix); List findByTenantIdAndEtagAndResourceKeyStartingWith(UUID tenantId, String etag, String query); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/resource/TbResourceRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/resource/TbResourceRepository.java index f6af27ab58..5cb32c0c10 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/resource/TbResourceRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/resource/TbResourceRepository.java @@ -26,7 +26,7 @@ import org.thingsboard.server.dao.model.sql.TbResourceEntity; import java.util.List; import java.util.UUID; -public interface TbResourceRepository extends JpaRepository , ExportableEntityRepository { +public interface TbResourceRepository extends JpaRepository, ExportableEntityRepository { TbResourceEntity findByTenantIdAndResourceTypeAndResourceKey(UUID tenantId, String resourceType, String resourceKey); @@ -94,8 +94,4 @@ public interface TbResourceRepository extends JpaRepository findIdsByTenantId(@Param("tenantId") UUID tenantId, Pageable pageable); - @Query("SELECT resourceKey FROM TbResourceInfoEntity WHERE tenantId = :tenantId AND resourceType = :resourceType AND resourceKey LIKE :resourceKeyPrefix ") - List findResourceKeys(@Param("tenantId")UUID tenantId, - @Param("resourceType") String resourceType, - @Param("resourceKeyPrefix") String resourceKeyPrefix); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java index 26a3924467..4d9510d0b1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java @@ -226,11 +226,6 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { tenantWidgetTypeRemover.removeEntities(tenantId, tenantId); } - @Override - public PageData findAllWidgetTypesIds(PageLink pageLink) { - return widgetTypeDao.findAllWidgetTypesIds(pageLink); - } - @Override public Optional> findEntity(TenantId tenantId, EntityId entityId) { return Optional.ofNullable(findWidgetTypeById(tenantId, new WidgetTypeId(entityId.getId()))); diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java index a2fcf6b374..468bea6876 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java @@ -75,7 +75,7 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService { log.trace("Executing saveWidgetsBundle [{}]", widgetsBundle); widgetsBundleValidator.validate(widgetsBundle, WidgetsBundle::getTenantId); try { - imageService.replaceBase64WithImageUrl(widgetsBundle, widgetsBundle.getName(), "bundle"); + imageService.replaceBase64WithImageUrl(widgetsBundle, "bundle"); WidgetsBundle result = widgetsBundleDao.save(widgetsBundle.getTenantId(), widgetsBundle); eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(result.getTenantId()) .entityId(result.getId()).added(widgetsBundle.getId() == null).build()); @@ -172,11 +172,6 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService { return widgetsBundles; } - @Override - public PageData findAllWidgetsBundles(PageLink pageLink) { - return widgetsBundleDao.findAllWidgetsBundles(pageLink); - } - @Override public void deleteWidgetsBundlesByTenantId(TenantId tenantId) { log.trace("Executing deleteWidgetsBundlesByTenantId, tenantId [{}]", tenantId);