From 588bc966814cd17bee71343700bf0892268106b8 Mon Sep 17 00:00:00 2001 From: nhthinh-axonivy Date: Wed, 11 Dec 2024 12:01:55 +0700 Subject: [PATCH 1/6] feature/IVYPORTAL-18050-Create-cache-mechanism-for-dashboard-converter-to-enhance-performance --- .../config/variables/Portal/Dashboard.json | 6 +- .../addon/portal/generic/menu/MenuView.java | 1 + .../generic/menu/PortalMenuNavigator.java | 32 +- .../portal/generic/bean/DashboardBean.java | 22 +- .../bean/DashboardDetailModificationBean.java | 13 +- .../bean/DashboardModificationBean.java | 17 +- .../portal/generic/bean/UserMenuBean.java | 4 +- .../constant/IvyCacheIdentifier.java | 1 + .../addon/portalkit/util/DashboardUtils.java | 282 +++++++----------- 9 files changed, 123 insertions(+), 255 deletions(-) diff --git a/AxonIvyPortal/portal/config/variables/Portal/Dashboard.json b/AxonIvyPortal/portal/config/variables/Portal/Dashboard.json index c222e3a9993..91c66496131 100644 --- a/AxonIvyPortal/portal/config/variables/Portal/Dashboard.json +++ b/AxonIvyPortal/portal/config/variables/Portal/Dashboard.json @@ -1,7 +1,7 @@ [ { "id": "1", - "version": "12.0.0", + "version": "11.0.0", "templateId": "default-portal-dashboard-template", "titles": [ { @@ -331,7 +331,7 @@ }, { "id": "default-task-list-dashboard", - "version": "12.0.0", + "version": "11.0.0", "templateId": "create-from-scratch", "titles": [ { @@ -443,7 +443,7 @@ }, { "id": "default-case-list-dashboard", - "version": "12.0.0", + "version": "11.0.0", "templateId": "create-from-scratch", "titles": [ { diff --git a/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/MenuView.java b/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/MenuView.java index 668df5c4364..a548c9d19f1 100644 --- a/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/MenuView.java +++ b/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/MenuView.java @@ -282,6 +282,7 @@ public void updateDashboardCache(List dashboards) { } cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_MENU, sessionUserId); + cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_DASHBOARD_CONVERTER_DATA, sessionUserId); } private String getSessionUserId() { diff --git a/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/PortalMenuNavigator.java b/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/PortalMenuNavigator.java index f627e684967..fd071c0c748 100644 --- a/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/PortalMenuNavigator.java +++ b/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/PortalMenuNavigator.java @@ -11,7 +11,6 @@ import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.UUID; import javax.faces.context.FacesContext; import javax.faces.event.ActionEvent; @@ -28,13 +27,10 @@ import ch.ivy.addon.portal.generic.navigation.PortalNavigator; import ch.ivy.addon.portalkit.comparator.ApplicationIndexAscendingComparator; import ch.ivy.addon.portalkit.configuration.Application; -import ch.ivy.addon.portalkit.constant.IvyCacheIdentifier; import ch.ivy.addon.portalkit.dto.DisplayName; import ch.ivy.addon.portalkit.dto.dashboard.Dashboard; import ch.ivy.addon.portalkit.enums.BreadCrumbKind; import ch.ivy.addon.portalkit.enums.MenuKind; -import ch.ivy.addon.portalkit.enums.SessionAttribute; -import ch.ivy.addon.portalkit.service.IvyCacheService; import ch.ivy.addon.portalkit.service.RegisteredApplicationService; import ch.ivy.addon.portalkit.util.DashboardUtils; import ch.ivy.addon.portalkit.util.PermissionUtils; @@ -111,35 +107,9 @@ public static List getThirdPartyApps() { } public static List callSubMenuItemsProcess() { - Locale requestLocale = Ivy.session().getContentLocale(); - String sessionIdAttribute = SessionAttribute.SESSION_IDENTIFIER.toString(); - if (Ivy.session().getAttribute(sessionIdAttribute) == null) { - Ivy.session().setAttribute(sessionIdAttribute, UUID.randomUUID().toString()); - } - String sessionUserId = (String) Ivy.session().getAttribute(sessionIdAttribute); - IvyCacheService cacheService = IvyCacheService.getInstance(); - PortalSubMenuItemWrapper portalSubMenuItemWrapper = null; - try { - portalSubMenuItemWrapper = (PortalSubMenuItemWrapper) cacheService - .getSessionCacheValue(IvyCacheIdentifier.PORTAL_MENU, sessionUserId).orElse(null); - } catch (ClassCastException e) { - cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_MENU, sessionUserId); - } - if (portalSubMenuItemWrapper == null || !requestLocale.equals(portalSubMenuItemWrapper.loadedLocale)) { - synchronized (PortalSubMenuItemWrapper.class) { - List subMenuItems = new ArrayList<>(); - try { subMenuItems = getSubmenuList(); - } catch (Exception e) { - Ivy.log().error("Cannot load SubMenuItems {0}", e.getMessage()); - } - - portalSubMenuItemWrapper = new PortalSubMenuItemWrapper(requestLocale, subMenuItems); - cacheService.setSessionCache(IvyCacheIdentifier.PORTAL_MENU, sessionUserId, portalSubMenuItemWrapper); - } - } - return portalSubMenuItemWrapper.portalSubMenuItems; + return subMenuItems; } public static void navigateToTargetPage(boolean isClickOnBreadcrumb, String destinationPage, diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardBean.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardBean.java index b573ec9dde1..a27f0884702 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardBean.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardBean.java @@ -45,7 +45,6 @@ import ch.ivy.addon.portalkit.exporter.Exporter; import ch.ivy.addon.portalkit.ivydata.service.impl.LanguageService; import ch.ivy.addon.portalkit.jsf.ManagedBeans; -import ch.ivy.addon.portalkit.persistence.converter.BusinessEntityConverter; import ch.ivy.addon.portalkit.service.GlobalSettingService; import ch.ivy.addon.portalkit.service.WidgetFilterService; import ch.ivy.addon.portalkit.support.HtmlParser; @@ -56,7 +55,6 @@ import ch.ivy.addon.portalkit.util.UrlUtils; import ch.ivy.addon.portalkit.util.UserUtils; import ch.ivyteam.ivy.environment.Ivy; -import ch.ivyteam.ivy.security.ISecurityConstants; import ch.ivyteam.ivy.security.IUser; import ch.ivyteam.ivy.workflow.ICase; import ch.ivyteam.ivy.workflow.ITask; @@ -139,18 +137,6 @@ public void loadDashboardTemplate() { this.dashboardTemplates = DashboardUtils.getDashboardTemplates(); } - protected List jsonToDashboards(String dashboardJSON) { - List mappingDashboards = BusinessEntityConverter.jsonValueToEntities(dashboardJSON, Dashboard.class); - for (Dashboard dashboard : mappingDashboards) { - if (CollectionUtils.isEmpty(dashboard.getPermissions())) { - ArrayList defaultPermissions = new ArrayList<>(); - defaultPermissions.add(ISecurityConstants.TOP_LEVEL_ROLE_NAME); - dashboard.setPermissions(defaultPermissions); - } - } - return mappingDashboards; - } - protected String readDashboardBySessionUser() { return currentUser().getProperty(PortalVariable.DASHBOARD.key); } @@ -169,16 +155,10 @@ protected void buildWidgetModels(Dashboard dashboard) { } protected List getVisiblePublicDashboards() { - String dashboardJson = Ivy.var().get(PortalVariable.DASHBOARD.key); - List visibleDashboards = DashboardUtils.getVisibleDashboards(dashboardJson); - setDashboardAsPublic(visibleDashboards); + List visibleDashboards = DashboardUtils.getVisibleDashboards(true); return visibleDashboards; } - private void setDashboardAsPublic(List visibleDashboards) { - visibleDashboards.stream().forEach(dashboard -> dashboard.setIsPublic(true)); - } - public List getDashboards() { return dashboards; } diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardDetailModificationBean.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardDetailModificationBean.java index 5727ffb6499..4a1565f3415 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardDetailModificationBean.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardDetailModificationBean.java @@ -176,13 +176,12 @@ protected List collectDashboards() { if (isPublicDashboard) { collectedDashboards = DashboardUtils.getPublicDashboards(); } else { - String dashboardInUserProperty = readDashboardBySessionUser(); - collectedDashboards = getVisibleDashboards(dashboardInUserProperty); + collectedDashboards = DashboardUtils.getPrivateDashboards(); } } catch (PortalException e) { Ivy.log().error(e); } - DashboardUtils.addDefaultTaskCaseListDashboardsIfMissing(collectedDashboards); + // DashboardUtils.addDefaultTaskCaseListDashboardsIfMissing(collectedDashboards); return collectedDashboards.stream() .filter(dashboard -> dashboard.getId().equals(selectedDashboardId)).collect(Collectors.toList()); } @@ -830,14 +829,6 @@ public void reloadParamtersFromProcessForCustomWidget(DashboardWidget widget) { customWidget.loadParametersFromProcess(); } - private List getVisibleDashboards(String dashboardJson) { - if (isPublicDashboard) { - return DashboardUtils.jsonToDashboards(dashboardJson); - } else { - return DashboardUtils.getVisibleDashboards(dashboardJson); - } - } - public void navigatetoDashboardConfigurationPage() throws IOException { String dashboardConfigurationUrl = PortalNavigator.buildDashboardConfigurationUrl(); FacesContext.getCurrentInstance().getExternalContext().redirect(dashboardConfigurationUrl); diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardModificationBean.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardModificationBean.java index c6c86eafd56..0fd4f824cf4 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardModificationBean.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardModificationBean.java @@ -69,13 +69,10 @@ public void initConfigration(boolean isPublicDashboard) { protected void collectDashboardsForManagement() { this.dashboards = new ArrayList<>(); - String dashboardInUserProperty = readDashboardBySessionUser(); if (isPublicDashboard) { - this.dashboards = DashboardUtils.getPublicDashboards(); - DashboardUtils.addDefaultTaskCaseListDashboardsIfMissing(this.dashboards); - } else if (StringUtils.isNoneEmpty(dashboardInUserProperty)) { - List myDashboards = getVisibleDashboards(dashboardInUserProperty); - this.dashboards.addAll(myDashboards); + this.dashboards = DashboardUtils.getVisibleDashboards(true); + } else { + this.dashboards = DashboardUtils.getVisibleDashboards(false); } } @@ -181,14 +178,6 @@ private void saveDashboards(List dashboards) { menuView.updateDashboardCache(DashboardUtils.collectDashboards()); } - private List getVisibleDashboards(String dashboardJson) { - if (isPublicDashboard) { - return DashboardUtils.jsonToDashboards(dashboardJson); - } else { - return DashboardUtils.getVisibleDashboards(dashboardJson); - } - } - public void navigateToDashboardDetailsPage(String dashboardId) { PortalNavigator.navigateToDashboardDetailsPage(dashboardId, isPublicDashboard); } diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/UserMenuBean.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/UserMenuBean.java index 08c315e2577..6ce1602afb6 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/UserMenuBean.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/UserMenuBean.java @@ -26,12 +26,12 @@ import ch.ivy.addon.portalkit.bean.PortalExceptionBean; import ch.ivy.addon.portalkit.dto.UserMenu; import ch.ivy.addon.portalkit.enums.GlobalVariable; +import ch.ivy.addon.portalkit.enums.SessionAttribute; import ch.ivy.addon.portalkit.jsf.Attrs; import ch.ivy.addon.portalkit.jsf.ManagedBeans; import ch.ivy.addon.portalkit.service.AnnouncementService; import ch.ivy.addon.portalkit.service.GlobalSettingService; import ch.ivy.addon.portalkit.service.IvyCacheService; -import ch.ivy.addon.portalkit.util.DashboardUtils; import ch.ivy.addon.portalkit.util.PermissionUtils; import ch.ivy.addon.portalkit.util.RequestUtils; import ch.ivy.addon.portalkit.util.TaskUtils; @@ -384,7 +384,7 @@ public String getGooglePlayImageLink() { } public String getInfoToHighlightMenu() { - return DashboardUtils.getSelectedMainDashboardIdFromSession(); + return (String) Ivy.session().getAttribute(SessionAttribute.SELECTED_DASHBOARD_ID.toString()); } public void navigateToChatBotOrDisplayWorkingTaskWarning(boolean isWorkingOnATask, ITask task) throws IOException { diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/constant/IvyCacheIdentifier.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/constant/IvyCacheIdentifier.java index cdd17232a67..24faff26a50 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/constant/IvyCacheIdentifier.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/constant/IvyCacheIdentifier.java @@ -11,6 +11,7 @@ public final class IvyCacheIdentifier { public static final String PORTAL_CUSTOM_MENU = "PORTAL_CUSTOM_MENU"; public static final String PORTAL_DASHBOARDS = "PORTAL_DASHBOARDS"; public static final String PORTAL_DASHBOARDS_MENU_ITEM = "PORTAL_DASHBOARDS_MENU_ITEM"; + public static final String PORTAL_DASHBOARD_CONVERTER_DATA = "PORTAL_DASHBOARD_CONVERTER_DATA"; // for caching locales public static final String PORTAL_CONTENT_LOCALES = "PORTAL_CONTENT_LOCALES"; diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java index f42e63ec3d2..6981e399f1f 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java @@ -8,7 +8,6 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.UUID; import java.util.function.Consumer; @@ -22,16 +21,12 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import ch.addon.portal.generic.menu.MenuView.PortalDashboardItemWrapper; -import ch.ivy.addon.portalkit.constant.IvyCacheIdentifier; import ch.ivy.addon.portalkit.dto.dashboard.Dashboard; import ch.ivy.addon.portalkit.dto.dashboard.DashboardOrder; import ch.ivy.addon.portalkit.dto.dashboard.DashboardTemplate; import ch.ivy.addon.portalkit.enums.PortalVariable; import ch.ivy.addon.portalkit.enums.SessionAttribute; import ch.ivy.addon.portalkit.persistence.converter.BusinessEntityConverter; -import ch.ivy.addon.portalkit.service.IvyCacheService; -import ch.ivy.addon.portalkit.service.exception.PortalException; import ch.ivyteam.ivy.environment.Ivy; import ch.ivyteam.ivy.security.ISecurityConstants; import ch.ivyteam.ivy.security.IUser; @@ -42,7 +37,8 @@ public class DashboardUtils { public final static String PARENT_DASHBOARD_MENU_POSTFIX = "-parent-dashboard"; public final static String MAIN_DASHBOARD_MENU_POSTFIX = "-main-dashboard"; public final static String SUB_DASHBOARD_MENU_POSTFIX = "-sub-dashboard"; - public final static String PARENT_DASHBOARD_MENU_PATTERN = DASHBOARD_MENU_PREFIX + "%s" + PARENT_DASHBOARD_MENU_POSTFIX; + public final static String PARENT_DASHBOARD_MENU_PATTERN = + DASHBOARD_MENU_PREFIX + "%s" + PARENT_DASHBOARD_MENU_POSTFIX; public final static String MAIN_DASHBOARD_MENU_PATTERN = DASHBOARD_MENU_PREFIX + "%s" + MAIN_DASHBOARD_MENU_POSTFIX; public final static String SUB_DASHBOARD_MENU_PATTERN = DASHBOARD_MENU_PREFIX + "%s" + SUB_DASHBOARD_MENU_POSTFIX; public final static String DASHBOARD_PAGE_URL = @@ -52,49 +48,72 @@ public class DashboardUtils { public final static String DEFAULT_TASK_LIST_DASHBOARD = "default-task-list-dashboard"; public final static String DEFAULT_CASE_LIST_DASHBOARD = "default-case-list-dashboard"; - public static List getVisibleDashboards(String dashboardJson) { + public static List getPublicDashboards() { + String dashboardJson = Ivy.var().get(PortalVariable.DASHBOARD.key); List dashboards = jsonToDashboards(dashboardJson); - dashboards.removeIf(dashboard -> { - List permissions = dashboard.getPermissions(); - if (permissions == null) { - return false; - } - return permissions.stream().noneMatch(DashboardUtils::isSessionUserHasPermisson); - }); + addDefaultTaskCaseListDashboardsIfMissing(dashboards); + setDashboardAsPublic(dashboards); return dashboards; } - private static boolean isSessionUserHasPermisson(String permission) { - return StringUtils.startsWith(permission, "#") ? StringUtils.equals(currentUser().getMemberName(), permission) - : PermissionUtils.doesSessionUserHaveRole(permission); + public static List getPrivateDashboards() { + String dashboardInUserProperty = readDashboardBySessionUser(); + List dashboards = jsonToDashboards(dashboardInUserProperty); + return dashboards; } - public static List jsonToDashboards(String dashboardJSON) { - if (StringUtils.isBlank(dashboardJSON)) { - return new ArrayList<>(); + public static List getVisibleDashboards(boolean isPublic) { + return isPublic ? getPublicDashboards() : getPrivateDashboards(); + } + + public static List collectDashboards() { + List dashboards = new ArrayList<>(); + dashboards.addAll(getVisibleDashboards(true)); // Public Dashboards + dashboards.addAll(getVisibleDashboards(false)); // Private Dashboards + + List dashboardOrders = getDashboardOrdersOfSessionUser(); + Map idToDashboard = createMapIdToDashboard(dashboards); + List collectedDashboards = new ArrayList<>(); + for (DashboardOrder dashboardOrder : dashboardOrders) { + if (dashboardOrder.getDashboardId() == null) { + continue; + } + Dashboard currentDashboard = idToDashboard.remove(dashboardOrder.getDashboardId()); + if (dashboardOrder.isVisible() && currentDashboard != null) { + collectedDashboards.add(currentDashboard); + } } + collectedDashboards.addAll(idToDashboard.values()); + addDefaultTaskCaseListDashboardsIfMissing(collectedDashboards); + return collectedDashboards; + } - List mappingDashboards = convertDashboardsToLatestVersion(dashboardJSON); - mappingDashboards.forEach(dashboard -> initDefaultPermission()); - return mappingDashboards; + public static List collectMainDashboards() { + return getPublicDashboards().stream().filter(Dashboard::getIsTopMenu).toList(); } - public static Dashboard jsonToDashboard(String dashboardJson) { - if (StringUtils.isBlank(dashboardJson)) { - return null; - } + public static List getDashboardsWithoutMenuItem() { + return collectDashboards().stream().filter(dashboard -> !dashboard.getIsTopMenu()).toList(); + } - ObjectMapper objectMapper = new ObjectMapper(); - Dashboard dashboard = null; + public static void highlightDashboardMenuItem(String selectedDashboardId) { + PrimeFaces.current().executeScript(String.format(HIGHLIGHT_DASHBOARD_ITEM_METHOD_PATTERN, selectedDashboardId)); + } + private static List jsonToDashboards(String dashboardJson) { + if (StringUtils.isBlank(dashboardJson)) { + return new ArrayList<>(); + } try { - dashboard = objectMapper.readValue(dashboardJson, Dashboard.class); - initDefaultPermission(); - } catch (IOException e) { - Ivy.log().error("Failed to read dashboard from JSON {0}", e, dashboardJson); + ObjectMapper mapper = new ObjectMapper(); + JsonDashboardMigrator migrator = new JsonDashboardMigrator(mapper.readTree(dashboardJson)); + List dashboards = BusinessEntityConverter.convertJsonNodeToList(migrator.migrate(), Dashboard.class); + dashboards.forEach(initDefaultPermission()); + return dashboards; + } catch (JsonProcessingException e) { + Ivy.log().error("Failed to parse dashboards from JSON: {0}", e); } - - return dashboard; + return new ArrayList<>(); } private static Consumer initDefaultPermission() { @@ -103,43 +122,11 @@ private static Consumer initDefaultPermission() { ArrayList defaultPermissions = new ArrayList<>(); defaultPermissions.add(ISecurityConstants.TOP_LEVEL_ROLE_NAME); dashboard.setPermissions(defaultPermissions); - } + } }; } - private static IUser currentUser() { - return Ivy.session().getSessionUser(); - } - - public static List getAllVisibleDashboardsOfSessionUser() { - List collectedDashboards = new ArrayList<>(); - String dashboardInUserProperty = readDashboardBySessionUser(); - try { - collectedDashboards.addAll(getVisiblePublicDashboards()); - collectedDashboards.addAll(jsonToDashboards(dashboardInUserProperty)); - } catch (PortalException e) { - // If errors like parsing JSON errors, ignore them - Ivy.log().error(e); - } - return collectedDashboards; - } - - public static List getVisiblePublicDashboards() { - String dashboardJson = Ivy.var().get(PortalVariable.DASHBOARD.key); - List visibleDashboards = getVisibleDashboards(dashboardJson); - setDashboardAsPublic(visibleDashboards); - return visibleDashboards; - } - - public static List getPublicDashboards() { - String dashboardJson = Ivy.var().get(PortalVariable.DASHBOARD.key); - List visibleDashboards = jsonToDashboards(dashboardJson); - addDefaultTaskCaseListDashboardsIfMissing(visibleDashboards); - setDashboardAsPublic(visibleDashboards); - return visibleDashboards; - } - - public static void addDefaultTaskCaseListDashboardsIfMissing(List dashboards) { + private static void addDefaultTaskCaseListDashboardsIfMissing(List dashboards) { if (!hasDashboardWithId(dashboards, DEFAULT_CASE_LIST_DASHBOARD)) { dashboards.add(0, DefaultDashboardUtils.getDefaultCaseListDashboard()); } @@ -152,18 +139,16 @@ private static boolean hasDashboardWithId(List dashboards, String id) return dashboards.stream().map(Dashboard::getId).anyMatch(dashboardId -> id.equals(dashboardId)); } - public static List getDashboardTemplates() { - String dashboardTemplatesJson = Ivy.var().get(PortalVariable.DASHBOARD_TEMPLATES.key); - return convertDashboardTemplatesToLatestVersion(dashboardTemplatesJson); + private static void setDashboardAsPublic(List dashboards) { + dashboards.forEach(dashboard -> dashboard.setIsPublic(true)); } - public static void setDashboardAsPublic(List visibleDashboards) { - visibleDashboards.forEach(dashboard -> dashboard.setIsPublic(true)); + private static String readDashboardBySessionUser() { + return Ivy.session().isSessionUserUnknown() ? "" : currentUser().getProperty(PortalVariable.DASHBOARD.key); } - public static List getDashboardOrdersOfSessionUser() { - var dashboardOrderJson = currentUser().getProperty(PortalVariable.DASHBOARD_ORDER.key); - return BusinessEntityConverter.jsonValueToEntities(dashboardOrderJson, DashboardOrder.class); + private static IUser currentUser() { + return Ivy.session().getSessionUser(); } public static Map createMapIdToDashboard(List dashboards) { @@ -172,45 +157,21 @@ public static Map createMapIdToDashboard(List dash return idToDashboard; } - public static String generateId() { - return UUID.randomUUID().toString().replace("-", ""); - } - - private static String readDashboardBySessionUser() { - if (Ivy.session().isSessionUserUnknown()) { - return ""; - } - return currentUser().getProperty(PortalVariable.DASHBOARD.key); + public static List getDashboardOrdersOfSessionUser() { + var dashboardOrderJson = currentUser().getProperty(PortalVariable.DASHBOARD_ORDER.key); + return BusinessEntityConverter.jsonValueToEntities(dashboardOrderJson, DashboardOrder.class); } - public static List collectDashboards() { - List visibleDashboards = getAllVisibleDashboardsOfSessionUser(); - List dashboardOrders = getDashboardOrdersOfSessionUser(); - Map idToDashboard = createMapIdToDashboard(visibleDashboards); - List collectedDashboards = new ArrayList<>(); - for (DashboardOrder dashboardOrder : dashboardOrders) { - if (dashboardOrder.getDashboardId() == null) { - continue; - } - Dashboard currentDashboard = idToDashboard.remove(dashboardOrder.getDashboardId()); - if (dashboardOrder.isVisible() && currentDashboard != null) { - collectedDashboards.add(currentDashboard); - } + public static List convertDashboardsFromUploadFileToLatestVersion(InputStream inputStream) + throws IOException { + try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) { + ObjectMapper mapper = new ObjectMapper(); + JsonDashboardMigrator migrator = new JsonDashboardMigrator(mapper.readTree(reader)); + return BusinessEntityConverter.convertJsonNodeToList(migrator.migrate(), Dashboard.class); + } catch (JsonProcessingException e) { + Ivy.log().error("Failed to read dashboard from JSON {0}", e); } - collectedDashboards.addAll(idToDashboard.values()); - addDefaultTaskCaseListDashboardsIfMissing(collectedDashboards); - return collectedDashboards; - } - - public static List collectMainDashboards() { - List collectedDashboards = - new ArrayList<>(getPublicDashboards().stream().filter(dashboard -> dashboard.getIsTopMenu()).toList()); - return collectedDashboards; - } - - - public static void highlightDashboardMenuItem(String selectedDashboardId) { - PrimeFaces.current().executeScript(String.format(HIGHLIGHT_DASHBOARD_ITEM_METHOD_PATTERN, selectedDashboardId)); + return null; } public static void updateSelectedDashboardToSession(String selectedMenuItemId) { @@ -229,39 +190,34 @@ public static void updateSelectedDashboardToSession(String selectedMenuItemId) { } } + public static void storeDashboardInSession(String dashboardId) { + Ivy.log().error("ADADA1" + dashboardId); + boolean isMain = isMainDashboard(dashboardId, true); + storeDashboardInSession(dashboardId, isMain); + } - public static List convertDashboardsToLatestVersion(String json) { - try { - ObjectMapper mapper = new ObjectMapper(); - JsonDashboardMigrator migrator = new JsonDashboardMigrator(mapper.readTree(json)); - return BusinessEntityConverter.convertJsonNodeToList(migrator.migrate(), Dashboard.class); - } catch (JsonProcessingException ex) { - Ivy.log().error("Failed to read dashboard from JSON {0}", ex, json); + public static void storeDashboardInSession(String dashboardId, boolean isMainDashboard) { + Ivy.session().setAttribute(SessionAttribute.SELECTED_DASHBOARD_ID.toString(), dashboardId); + + if (!isMainDashboard) { + + Ivy.session().setAttribute(SessionAttribute.SELECTED_SUB_DASHBOARD_ID.toString(), dashboardId); } - return null; } - public static List convertDashboardsFromUploadFileToLatestVersion(InputStream inputStream) - throws IOException { - try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) { - ObjectMapper mapper = new ObjectMapper(); - JsonDashboardMigrator migrator = new JsonDashboardMigrator(mapper.readTree(reader)); - return BusinessEntityConverter.convertJsonNodeToList(migrator.migrate(), Dashboard.class); - } catch (JsonProcessingException e) { - Ivy.log().error("Failed to read dashboard from JSON {0}", e); + public static boolean isMainDashboard(String dashboardId, boolean defaultValue) { + if (StringUtils.isEmpty(dashboardId)) { + + return false; } - return null; + + return collectMainDashboards().stream().filter(dashboard -> dashboardId.equals(dashboard.getId())) + .map(Dashboard::getIsTopMenu).findFirst().orElse(defaultValue); } - public static Dashboard convertDashboardToLatestVersion(InputStream inputStream) throws IOException { - try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) { - ObjectMapper mapper = new ObjectMapper(); - JsonDashboardMigrator migrator = new JsonDashboardMigrator(mapper.readTree(reader)); - return BusinessEntityConverter.convertJsonNodeToEntity(migrator.migrate(), Dashboard.class); - } catch (JsonProcessingException ex) { - Ivy.log().error("Failed to read dashboard from JSON {0}", ex); - } - return null; + public static List getDashboardTemplates() { + String dashboardTemplatesJson = Ivy.var().get(PortalVariable.DASHBOARD_TEMPLATES.key); + return convertDashboardTemplatesToLatestVersion(dashboardTemplatesJson); } private static List convertDashboardTemplatesToLatestVersion(String json) { @@ -275,47 +231,28 @@ private static List convertDashboardTemplatesToLatestVersion( return null; } - public static void storeDashboardInSession(String id) { - storeDashboardInSession(id, isMainDashboard(id, true)); + public static String generateId() { + return UUID.randomUUID().toString().replace("-", ""); } - public static void storeDashboardInSession(String id, boolean isMainDashboard) { - Ivy.session().setAttribute(SessionAttribute.SELECTED_DASHBOARD_ID.toString(), id); - if (!isMainDashboard) { - Ivy.session().setAttribute(SessionAttribute.SELECTED_SUB_DASHBOARD_ID.toString(), id); + public static Dashboard jsonToDashboard(String dashboardJson) { + if (StringUtils.isBlank(dashboardJson)) { + return null; } - } - - public static List getDashboardsWithoutMenuItem() { - var dashboards = collectDashboards(); - return dashboards.stream().filter(dashboard -> !dashboard.getIsTopMenu()).toList(); - } - - public static String getSelectedMainDashboardIdFromSession() { - return (String) Ivy.session().getAttribute(SessionAttribute.SELECTED_DASHBOARD_ID.toString()); - } - private static PortalDashboardItemWrapper getPortalDashboardItemWrapper() { - String sessionUserId = UserUtils.getSessionIdentifierAttribteWithInitIfEmpty(); - return (PortalDashboardItemWrapper) IvyCacheService.getInstance() - .getSessionCacheValue(IvyCacheIdentifier.PORTAL_DASHBOARDS, sessionUserId).orElse(null); - } + ObjectMapper objectMapper = new ObjectMapper(); + Dashboard dashboard = null; - public static boolean isMainDashboard(String dashboardId, boolean defaultValue) { - if (StringUtils.isEmpty(dashboardId)) { - return false; + try { + dashboard = objectMapper.readValue(dashboardJson, Dashboard.class); + initDefaultPermission(); + } catch (IOException e) { + Ivy.log().error("Failed to read dashboard from JSON {0}", e, dashboardJson); } - boolean isMainDashboard = Optional.ofNullable(getPortalDashboardItemWrapper()) - .map(wrapper -> wrapper.dashboards()).orElse(new ArrayList<>()).stream() - .filter(dashboard -> dashboardId.equals(dashboard.getId())).map(dashboard -> dashboard.getIsTopMenu()) - .findFirst().orElse(defaultValue); - return isMainDashboard; - } + return dashboard; + } - /** - * Uses this method before saving a dashboard to simplify generated json from the dashboard - */ public static void updatePropertiesToNullIfCurrentValueIsDefaultValue(List dashboards) { if (CollectionUtils.isEmpty(dashboards)) { return; @@ -326,5 +263,4 @@ public static void updatePropertiesToNullIfCurrentValueIsDefaultValue(List Date: Wed, 11 Dec 2024 18:22:19 +0700 Subject: [PATCH 2/6] feature/IVYPORTAL-18050-Create-cache-mechanism-for-dashboard-converter-to-enhance-performance _ refactor dashboard utils _ remove unuse code _ unify collect dashboards data into collect public and private _ remove old cache _ apdat new cache for getPublic and getPrivate dashboard --- .../addon/portal/generic/menu/MenuView.java | 41 +------ .../generic/menu/PortalMenuNavigator.java | 8 +- .../portal/generic/bean/DashboardBean.java | 8 -- .../constant/IvyCacheIdentifier.java | 6 +- .../portalkit/dto/dashboard/Dashboard.java | 2 +- .../addon/portalkit/util/DashboardUtils.java | 103 +++++++++++++++--- 6 files changed, 96 insertions(+), 72 deletions(-) diff --git a/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/MenuView.java b/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/MenuView.java index a548c9d19f1..ee6f01b2903 100644 --- a/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/MenuView.java +++ b/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/MenuView.java @@ -152,7 +152,7 @@ private MenuElement buildDashboardItem() { String mainMenuDisplayName = mainMenuEntryService.getNameInCurrentLocale(); String mainMenuIcon = mainMenuEntryService.getMenuIcon(); - var subItemDashboards = getSubItemDashboards(); + List subItemDashboards = getSubItemDashboards(); if (subItemDashboards.size() > 1) { return buildDashboardGroupMenu(subItemDashboards, dashboardTitle, mainMenuDisplayName, mainMenuIcon, currentLanguage, dashboardLink); @@ -173,8 +173,8 @@ private String determineDashboardLink() { } private List getSubItemDashboards() { - var dashboards = getDashboardCache().dashboards; - return dashboards.stream().filter(dashboard -> !dashboard.getIsTopMenu()).toList(); + List dashboards = DashboardUtils.getDashboardsWithoutMenuItem(); + return dashboards; } private MenuElement buildDashboardGroupMenu(List subItemDashboards, String defaultTitle, @@ -252,37 +252,13 @@ private MenuElement buildSingleDashboardMenu(String dashboardTitle, String dashb return dashboardMenu; } - - public PortalDashboardItemWrapper getDashboardCache() { - String sessionUserId = getSessionUserId(); - IvyCacheService cacheService = IvyCacheService.getInstance(); - PortalDashboardItemWrapper portalDashboardItemWrapper = null; - try { - portalDashboardItemWrapper = getPortalDashboardItemWrapper(sessionUserId, cacheService); - } catch (ClassCastException e) { - cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_MENU, sessionUserId); - } - - if (portalDashboardItemWrapper == null) { - synchronized(PortalDashboardItemWrapper.class) { - portalDashboardItemWrapper = new PortalDashboardItemWrapper(DashboardUtils.collectDashboards()); - cacheService.setSessionCache(IvyCacheIdentifier.PORTAL_DASHBOARDS, sessionUserId, portalDashboardItemWrapper); - } - } - return portalDashboardItemWrapper; - } - public void updateDashboardCache(List dashboards) { String sessionUserId = getSessionUserId(); IvyCacheService cacheService = IvyCacheService.getInstance(); - synchronized (PortalDashboardItemWrapper.class) { - cacheService.setSessionCache(IvyCacheIdentifier.PORTAL_DASHBOARDS, sessionUserId, - new PortalDashboardItemWrapper(dashboards)); - } + cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_PUBLIC_DASHBOARD, sessionUserId); + cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_PRIVATE_DASHBOARD, sessionUserId); - cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_MENU, sessionUserId); - cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_DASHBOARD_CONVERTER_DATA, sessionUserId); } private String getSessionUserId() { @@ -293,10 +269,6 @@ private String getSessionUserId() { return (String) session().getAttribute(sessionIdAttribute); } - private PortalDashboardItemWrapper getPortalDashboardItemWrapper(String sessionUserId, IvyCacheService cacheService) { - return (PortalDashboardItemWrapper) cacheService.getSessionCacheValue(IvyCacheIdentifier.PORTAL_DASHBOARDS, sessionUserId).orElse(null); - } - public String getDashboardLink() { return PortalNavigator.getDashboardLink(); } @@ -519,9 +491,6 @@ private IWorkflowSession session() { return Ivy.session(); } - public record PortalDashboardItemWrapper(List dashboards) { - } - private void buildBreadCrumbForNotification() { setPortalHomeMenuToBreadcrumbModel(); breadcrumbModel.getElements().add(buildGenericMenuItem("/ch.ivy.addon.portalkit.ui.jsf/notifications/notificationTitle")); diff --git a/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/PortalMenuNavigator.java b/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/PortalMenuNavigator.java index fd071c0c748..db2468c77ec 100644 --- a/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/PortalMenuNavigator.java +++ b/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/PortalMenuNavigator.java @@ -9,7 +9,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Locale; import java.util.Map; import javax.faces.context.FacesContext; @@ -107,8 +106,8 @@ public static List getThirdPartyApps() { } public static List callSubMenuItemsProcess() { - - subMenuItems = getSubmenuList(); + List subMenuItems = new ArrayList<>(); + subMenuItems = getSubmenuList(); return subMenuItems; } @@ -126,9 +125,6 @@ public static void navigateToTargetPage(boolean isClickOnBreadcrumb, String dest navigateToTargetPage(params); } - private record PortalSubMenuItemWrapper(Locale loadedLocale, List portalSubMenuItems) { - } - private static List getSubmenuList() { String currentLanguage = UserUtils.getUserLanguage(); List subMenuItems = new ArrayList<>(); diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardBean.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardBean.java index a27f0884702..586c4ba0c41 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardBean.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardBean.java @@ -22,7 +22,6 @@ import com.axonivy.portal.dto.dashboard.filter.DashboardFilter; import com.axonivy.portal.service.DeepLTranslationService; -import ch.addon.portal.generic.menu.MenuView; import ch.ivy.addon.portal.generic.navigation.PortalNavigator; import ch.ivy.addon.portalkit.constant.PortalConstants; import ch.ivy.addon.portalkit.dto.DisplayName; @@ -44,7 +43,6 @@ import ch.ivy.addon.portalkit.enums.TaskEmptyMessage; import ch.ivy.addon.portalkit.exporter.Exporter; import ch.ivy.addon.portalkit.ivydata.service.impl.LanguageService; -import ch.ivy.addon.portalkit.jsf.ManagedBeans; import ch.ivy.addon.portalkit.service.GlobalSettingService; import ch.ivy.addon.portalkit.service.WidgetFilterService; import ch.ivy.addon.portalkit.support.HtmlParser; @@ -89,12 +87,6 @@ public void init() { currentDashboardIndex = 0; dashboards = collectDashboards(); - - if (isReadOnlyMode) { - MenuView menuView = (MenuView) ManagedBeans.get("menuView"); - menuView.updateDashboardCache(dashboards); - } - if (CollectionUtils.isNotEmpty(DashboardUtils.getDashboardsWithoutMenuItem())) { updateSelectedDashboardIdFromSessionAttribute(); currentDashboardIndex = findIndexOfDashboardById(selectedDashboardId); diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/constant/IvyCacheIdentifier.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/constant/IvyCacheIdentifier.java index 24faff26a50..6bcd5d20226 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/constant/IvyCacheIdentifier.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/constant/IvyCacheIdentifier.java @@ -9,10 +9,8 @@ public final class IvyCacheIdentifier { public static final String ROLES_IN_SECURITY_CONTEXT = "ROLES_IN_SECURITY_CONTEXT"; public static final String PORTAL_MENU = "PORTAL_MENU"; public static final String PORTAL_CUSTOM_MENU = "PORTAL_CUSTOM_MENU"; - public static final String PORTAL_DASHBOARDS = "PORTAL_DASHBOARDS"; - public static final String PORTAL_DASHBOARDS_MENU_ITEM = "PORTAL_DASHBOARDS_MENU_ITEM"; - public static final String PORTAL_DASHBOARD_CONVERTER_DATA = "PORTAL_DASHBOARD_CONVERTER_DATA"; - + public static final String PORTAL_PUBLIC_DASHBOARD = "PORTAL_PUBLIC_DASHBOARD"; + public static final String PORTAL_PRIVATE_DASHBOARD = "PORTAL_PRIVATE_DASHBOARD"; // for caching locales public static final String PORTAL_CONTENT_LOCALES = "PORTAL_CONTENT_LOCALES"; public static final String PORTAL_FORMATTING_LOCALES = "PORTAL_FORMATTING_LOCALES"; diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/dto/dashboard/Dashboard.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/dto/dashboard/Dashboard.java index 0896ec2dc67..3134cd3d517 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/dto/dashboard/Dashboard.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/dto/dashboard/Dashboard.java @@ -139,7 +139,7 @@ public void setTemplateId(String templateId) { } public Boolean getIsTopMenu() { - return isTopMenu; + return isTopMenu != null ? isTopMenu : false; } public void setIsTopMenu(Boolean isTopMenu) { diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java index 6981e399f1f..61f1a53baa7 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.UUID; import java.util.function.Consumer; @@ -21,12 +22,14 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import ch.ivy.addon.portalkit.constant.IvyCacheIdentifier; import ch.ivy.addon.portalkit.dto.dashboard.Dashboard; import ch.ivy.addon.portalkit.dto.dashboard.DashboardOrder; import ch.ivy.addon.portalkit.dto.dashboard.DashboardTemplate; import ch.ivy.addon.portalkit.enums.PortalVariable; import ch.ivy.addon.portalkit.enums.SessionAttribute; import ch.ivy.addon.portalkit.persistence.converter.BusinessEntityConverter; +import ch.ivy.addon.portalkit.service.IvyCacheService; import ch.ivyteam.ivy.environment.Ivy; import ch.ivyteam.ivy.security.ISecurityConstants; import ch.ivyteam.ivy.security.IUser; @@ -49,17 +52,72 @@ public class DashboardUtils { public final static String DEFAULT_CASE_LIST_DASHBOARD = "default-case-list-dashboard"; public static List getPublicDashboards() { - String dashboardJson = Ivy.var().get(PortalVariable.DASHBOARD.key); - List dashboards = jsonToDashboards(dashboardJson); - addDefaultTaskCaseListDashboardsIfMissing(dashboards); - setDashboardAsPublic(dashboards); - return dashboards; + Locale requestLocale = Ivy.session().getContentLocale(); + String sessionIdAttribute = SessionAttribute.SESSION_IDENTIFIER.toString(); + if (Ivy.session().getAttribute(sessionIdAttribute) == null) { + Ivy.session().setAttribute(sessionIdAttribute, UUID.randomUUID().toString()); + } + String sessionUserId = (String) Ivy.session().getAttribute(sessionIdAttribute); + IvyCacheService cacheService = IvyCacheService.getInstance(); + PortalPublicDashboardWrapper portalPublicDashboardWrapper = null; + try { + portalPublicDashboardWrapper = (PortalPublicDashboardWrapper) cacheService + .getSessionCacheValue(IvyCacheIdentifier.PORTAL_PUBLIC_DASHBOARD, sessionUserId).orElse(null); + } catch (ClassCastException e) { + cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_PUBLIC_DASHBOARD, sessionUserId); + } + + if (portalPublicDashboardWrapper == null || !requestLocale.equals(portalPublicDashboardWrapper.loadedLocale)) { + synchronized (PortalPublicDashboardWrapper.class) { + List dashboards = new ArrayList<>(); + try { + String dashboardJson = Ivy.var().get(PortalVariable.DASHBOARD.key); + dashboards = jsonToDashboards(dashboardJson); + ensureDefaultIsTopMenu(dashboards); + addDefaultTaskCaseListDashboardsIfMissing(dashboards); + setDashboardAsPublic(dashboards); + } catch (Exception e) { + Ivy.log().error("Cannot load Public Dashboards {0}", e.getMessage()); + } + portalPublicDashboardWrapper = new PortalPublicDashboardWrapper(requestLocale, dashboards); + cacheService.setSessionCache(IvyCacheIdentifier.PORTAL_PUBLIC_DASHBOARD, sessionUserId, + portalPublicDashboardWrapper); + } + } + return portalPublicDashboardWrapper.dashboards(); } public static List getPrivateDashboards() { - String dashboardInUserProperty = readDashboardBySessionUser(); - List dashboards = jsonToDashboards(dashboardInUserProperty); - return dashboards; + Locale requestLocale = Ivy.session().getContentLocale(); + String sessionIdAttribute = SessionAttribute.SESSION_IDENTIFIER.toString(); + if (Ivy.session().getAttribute(sessionIdAttribute) == null) { + Ivy.session().setAttribute(sessionIdAttribute, UUID.randomUUID().toString()); + } + String sessionUserId = (String) Ivy.session().getAttribute(sessionIdAttribute); + IvyCacheService cacheService = IvyCacheService.getInstance(); + PortalPrivateDashboardWrapper portalPrivateDashboardWrapper = null; + try { + portalPrivateDashboardWrapper = (PortalPrivateDashboardWrapper) cacheService + .getSessionCacheValue(IvyCacheIdentifier.PORTAL_PRIVATE_DASHBOARD, sessionUserId).orElse(null); + } catch (ClassCastException e) { + cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_PRIVATE_DASHBOARD, sessionUserId); + } + + if (portalPrivateDashboardWrapper == null || !requestLocale.equals(portalPrivateDashboardWrapper.loadedLocale)) { + synchronized (PortalPublicDashboardWrapper.class) { + List dashboards = new ArrayList<>(); + try { + String dashboardInUserProperty = readDashboardBySessionUser(); + dashboards = jsonToDashboards(dashboardInUserProperty); + } catch (Exception e) { + Ivy.log().error("Cannot load Public Dashboards {0}", e.getMessage()); + } + portalPrivateDashboardWrapper = new PortalPrivateDashboardWrapper(requestLocale, dashboards); + cacheService.setSessionCache(IvyCacheIdentifier.PORTAL_PRIVATE_DASHBOARD, sessionUserId, + portalPrivateDashboardWrapper); + } + } + return portalPrivateDashboardWrapper.dashboards(); } public static List getVisibleDashboards(boolean isPublic) { @@ -81,7 +139,7 @@ public static List collectDashboards() { Dashboard currentDashboard = idToDashboard.remove(dashboardOrder.getDashboardId()); if (dashboardOrder.isVisible() && currentDashboard != null) { collectedDashboards.add(currentDashboard); - } + } } collectedDashboards.addAll(idToDashboard.values()); addDefaultTaskCaseListDashboardsIfMissing(collectedDashboards); @@ -102,7 +160,7 @@ public static void highlightDashboardMenuItem(String selectedDashboardId) { private static List jsonToDashboards(String dashboardJson) { if (StringUtils.isBlank(dashboardJson)) { - return new ArrayList<>(); + return new ArrayList<>(); } try { ObjectMapper mapper = new ObjectMapper(); @@ -122,7 +180,7 @@ private static Consumer initDefaultPermission() { ArrayList defaultPermissions = new ArrayList<>(); defaultPermissions.add(ISecurityConstants.TOP_LEVEL_ROLE_NAME); dashboard.setPermissions(defaultPermissions); - } + } }; } @@ -191,26 +249,21 @@ public static void updateSelectedDashboardToSession(String selectedMenuItemId) { } public static void storeDashboardInSession(String dashboardId) { - Ivy.log().error("ADADA1" + dashboardId); - boolean isMain = isMainDashboard(dashboardId, true); + boolean isMain = isMainDashboard(dashboardId, false); storeDashboardInSession(dashboardId, isMain); } public static void storeDashboardInSession(String dashboardId, boolean isMainDashboard) { Ivy.session().setAttribute(SessionAttribute.SELECTED_DASHBOARD_ID.toString(), dashboardId); - if (!isMainDashboard) { - Ivy.session().setAttribute(SessionAttribute.SELECTED_SUB_DASHBOARD_ID.toString(), dashboardId); } } public static boolean isMainDashboard(String dashboardId, boolean defaultValue) { if (StringUtils.isEmpty(dashboardId)) { - return false; } - return collectMainDashboards().stream().filter(dashboard -> dashboardId.equals(dashboard.getId())) .map(Dashboard::getIsTopMenu).findFirst().orElse(defaultValue); } @@ -263,4 +316,20 @@ public static void updatePropertiesToNullIfCurrentValueIsDefaultValue(List dashboards) { + if (dashboards != null) { + dashboards.forEach(dashboard -> { + if (dashboard.getIsTopMenu() == null) { + dashboard.setIsTopMenu(false); + } + }); + } + } + + private record PortalPrivateDashboardWrapper(Locale loadedLocale, List dashboards) { + } + private record PortalPublicDashboardWrapper(Locale loadedLocale, List dashboards) { + } + } From 429038d2e7daac43cbfbf28091ad62fc80f7adfc Mon Sep 17 00:00:00 2001 From: nhthinh-axonivy Date: Wed, 11 Dec 2024 18:23:37 +0700 Subject: [PATCH 3/6] feature/IVYPORTAL-18050-Create-cache-mechanism-for-dashboard-converter-to-enhance-performance --- AxonIvyPortal/portal/config/variables/Portal/Dashboard.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AxonIvyPortal/portal/config/variables/Portal/Dashboard.json b/AxonIvyPortal/portal/config/variables/Portal/Dashboard.json index 91c66496131..c222e3a9993 100644 --- a/AxonIvyPortal/portal/config/variables/Portal/Dashboard.json +++ b/AxonIvyPortal/portal/config/variables/Portal/Dashboard.json @@ -1,7 +1,7 @@ [ { "id": "1", - "version": "11.0.0", + "version": "12.0.0", "templateId": "default-portal-dashboard-template", "titles": [ { @@ -331,7 +331,7 @@ }, { "id": "default-task-list-dashboard", - "version": "11.0.0", + "version": "12.0.0", "templateId": "create-from-scratch", "titles": [ { @@ -443,7 +443,7 @@ }, { "id": "default-case-list-dashboard", - "version": "11.0.0", + "version": "12.0.0", "templateId": "create-from-scratch", "titles": [ { From a8574904b3d3c663a2053add3553497db1e27e57 Mon Sep 17 00:00:00 2001 From: nhthinh-axonivy Date: Wed, 11 Dec 2024 18:48:26 +0700 Subject: [PATCH 4/6] feature/IVYPORTAL-18050-Create-cache-mechanism-for-dashboard-converter-to-enhance-performance --- .../generic/bean/DashboardModificationBean.java | 4 ++-- .../ivy/addon/portalkit/dto/dashboard/Dashboard.java | 2 +- .../ch/ivy/addon/portalkit/util/DashboardUtils.java | 12 +----------- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardModificationBean.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardModificationBean.java index 0fd4f824cf4..58c9a2ec3d0 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardModificationBean.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardModificationBean.java @@ -395,8 +395,8 @@ public void savePublicArrangement() { } } newDashboards.addAll(idToDashboard.values()); - String dashboardsAsSJSON = BusinessEntityConverter.entityToJsonValue(newDashboards); - Ivy.var().set(PortalVariable.DASHBOARD.key, dashboardsAsSJSON); + + saveDashboards(newDashboards); } public void savePrivateArrangement() { diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/dto/dashboard/Dashboard.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/dto/dashboard/Dashboard.java index 3134cd3d517..0896ec2dc67 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/dto/dashboard/Dashboard.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/dto/dashboard/Dashboard.java @@ -139,7 +139,7 @@ public void setTemplateId(String templateId) { } public Boolean getIsTopMenu() { - return isTopMenu != null ? isTopMenu : false; + return isTopMenu; } public void setIsTopMenu(Boolean isTopMenu) { diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java index 61f1a53baa7..08e87c70280 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java @@ -73,7 +73,6 @@ public static List getPublicDashboards() { try { String dashboardJson = Ivy.var().get(PortalVariable.DASHBOARD.key); dashboards = jsonToDashboards(dashboardJson); - ensureDefaultIsTopMenu(dashboards); addDefaultTaskCaseListDashboardsIfMissing(dashboards); setDashboardAsPublic(dashboards); } catch (Exception e) { @@ -167,6 +166,7 @@ private static List jsonToDashboards(String dashboardJson) { JsonDashboardMigrator migrator = new JsonDashboardMigrator(mapper.readTree(dashboardJson)); List dashboards = BusinessEntityConverter.convertJsonNodeToList(migrator.migrate(), Dashboard.class); dashboards.forEach(initDefaultPermission()); + return dashboards; } catch (JsonProcessingException e) { Ivy.log().error("Failed to parse dashboards from JSON: {0}", e); @@ -317,16 +317,6 @@ public static void updatePropertiesToNullIfCurrentValueIsDefaultValue(List dashboards) { - if (dashboards != null) { - dashboards.forEach(dashboard -> { - if (dashboard.getIsTopMenu() == null) { - dashboard.setIsTopMenu(false); - } - }); - } - } - private record PortalPrivateDashboardWrapper(Locale loadedLocale, List dashboards) { } private record PortalPublicDashboardWrapper(Locale loadedLocale, List dashboards) { From 80bc517a948df14c278b8802afd2ede1b8cb5692 Mon Sep 17 00:00:00 2001 From: nhthinh-axonivy Date: Tue, 17 Dec 2024 09:59:16 +0700 Subject: [PATCH 5/6] feature/IVYPORTAL-18050-Create-cache-mechanism-for-dashboard-converter-to-enhance-performance --- .../addon/portal/generic/menu/MenuView.java | 34 +++++++++++++++++-- .../portal/generic/bean/DashboardBean.java | 7 ++++ .../bean/DashboardDetailModificationBean.java | 19 +---------- .../bean/DashboardWelcomeWidgetBean.java | 1 - .../constant/IvyCacheIdentifier.java | 3 +- .../addon/portalkit/util/DashboardUtils.java | 15 ++++---- 6 files changed, 47 insertions(+), 32 deletions(-) diff --git a/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/MenuView.java b/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/MenuView.java index ee6f01b2903..2e1ce84414f 100644 --- a/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/MenuView.java +++ b/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/MenuView.java @@ -173,8 +173,8 @@ private String determineDashboardLink() { } private List getSubItemDashboards() { - List dashboards = DashboardUtils.getDashboardsWithoutMenuItem(); - return dashboards; + var dashboards = getDashboardCache().dashboards; + return dashboards.stream().filter(dashboard -> !dashboard.getIsTopMenu()).toList(); } private MenuElement buildDashboardGroupMenu(List subItemDashboards, String defaultTitle, @@ -252,10 +252,30 @@ private MenuElement buildSingleDashboardMenu(String dashboardTitle, String dashb return dashboardMenu; } - public void updateDashboardCache(List dashboards) { + + public PortalDashboardItemWrapper getDashboardCache() { String sessionUserId = getSessionUserId(); IvyCacheService cacheService = IvyCacheService.getInstance(); + PortalDashboardItemWrapper portalDashboardItemWrapper = null; + try { + portalDashboardItemWrapper = getPortalDashboardItemWrapper(sessionUserId, cacheService); + } catch (ClassCastException e) { + cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_DASHBOARDS, sessionUserId); + } + + if (portalDashboardItemWrapper == null) { + synchronized (PortalDashboardItemWrapper.class) { + portalDashboardItemWrapper = new PortalDashboardItemWrapper(DashboardUtils.collectDashboards()); + cacheService.setSessionCache(IvyCacheIdentifier.PORTAL_DASHBOARDS, sessionUserId, portalDashboardItemWrapper); + } + } + return portalDashboardItemWrapper; + } + public void updateDashboardCache(List dashboards) { + String sessionUserId = getSessionUserId(); + IvyCacheService cacheService = IvyCacheService.getInstance(); + cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_DASHBOARDS, sessionUserId); cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_PUBLIC_DASHBOARD, sessionUserId); cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_PRIVATE_DASHBOARD, sessionUserId); @@ -269,6 +289,11 @@ private String getSessionUserId() { return (String) session().getAttribute(sessionIdAttribute); } + private PortalDashboardItemWrapper getPortalDashboardItemWrapper(String sessionUserId, IvyCacheService cacheService) { + return (PortalDashboardItemWrapper) cacheService + .getSessionCacheValue(IvyCacheIdentifier.PORTAL_DASHBOARDS, sessionUserId).orElse(null); + } + public String getDashboardLink() { return PortalNavigator.getDashboardLink(); } @@ -491,6 +516,9 @@ private IWorkflowSession session() { return Ivy.session(); } + public record PortalDashboardItemWrapper(List dashboards) { + } + private void buildBreadCrumbForNotification() { setPortalHomeMenuToBreadcrumbModel(); breadcrumbModel.getElements().add(buildGenericMenuItem("/ch.ivy.addon.portalkit.ui.jsf/notifications/notificationTitle")); diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardBean.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardBean.java index 586c4ba0c41..a68c30f0a4d 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardBean.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardBean.java @@ -22,6 +22,7 @@ import com.axonivy.portal.dto.dashboard.filter.DashboardFilter; import com.axonivy.portal.service.DeepLTranslationService; +import ch.addon.portal.generic.menu.MenuView; import ch.ivy.addon.portal.generic.navigation.PortalNavigator; import ch.ivy.addon.portalkit.constant.PortalConstants; import ch.ivy.addon.portalkit.dto.DisplayName; @@ -43,6 +44,7 @@ import ch.ivy.addon.portalkit.enums.TaskEmptyMessage; import ch.ivy.addon.portalkit.exporter.Exporter; import ch.ivy.addon.portalkit.ivydata.service.impl.LanguageService; +import ch.ivy.addon.portalkit.jsf.ManagedBeans; import ch.ivy.addon.portalkit.service.GlobalSettingService; import ch.ivy.addon.portalkit.service.WidgetFilterService; import ch.ivy.addon.portalkit.support.HtmlParser; @@ -87,6 +89,11 @@ public void init() { currentDashboardIndex = 0; dashboards = collectDashboards(); + if (isReadOnlyMode) { + MenuView menuView = (MenuView) ManagedBeans.get("menuView"); + menuView.updateDashboardCache(dashboards); + } + if (CollectionUtils.isNotEmpty(DashboardUtils.getDashboardsWithoutMenuItem())) { updateSelectedDashboardIdFromSessionAttribute(); currentDashboardIndex = findIndexOfDashboardById(selectedDashboardId); diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardDetailModificationBean.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardDetailModificationBean.java index 4a1565f3415..5d14acd6334 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardDetailModificationBean.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/DashboardDetailModificationBean.java @@ -86,9 +86,7 @@ import ch.ivy.addon.portalkit.jsf.Attrs; import ch.ivy.addon.portalkit.jsf.ManagedBeans; import ch.ivy.addon.portalkit.service.DashboardService; -import ch.ivy.addon.portalkit.service.exception.PortalException; import ch.ivy.addon.portalkit.util.CustomWidgetUtils; -import ch.ivy.addon.portalkit.util.DashboardUtils; import ch.ivy.addon.portalkit.util.DashboardWidgetUtils; import ch.ivy.addon.portalkit.util.Dates; import ch.ivy.addon.portalkit.util.UserUtils; @@ -169,22 +167,7 @@ private Function convertToDashboardProcess() { }; } - @Override - protected List collectDashboards() { - List collectedDashboards = new ArrayList<>(); - try { - if (isPublicDashboard) { - collectedDashboards = DashboardUtils.getPublicDashboards(); - } else { - collectedDashboards = DashboardUtils.getPrivateDashboards(); - } - } catch (PortalException e) { - Ivy.log().error(e); - } - // DashboardUtils.addDefaultTaskCaseListDashboardsIfMissing(collectedDashboards); - return collectedDashboards.stream() - .filter(dashboard -> dashboard.getId().equals(selectedDashboardId)).collect(Collectors.toList()); - } + private WidgetSample taskSample() { return new WidgetSample(translate("/ch.ivy.addon.portalkit.ui.jsf/dashboard/taskList"), TASK, diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/bean/DashboardWelcomeWidgetBean.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/bean/DashboardWelcomeWidgetBean.java index 882a7dd780d..f3f230eef50 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/bean/DashboardWelcomeWidgetBean.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/bean/DashboardWelcomeWidgetBean.java @@ -96,7 +96,6 @@ private void removeImageContentOfWidget(ContentObject imageContent) { } String dashboardJson = BusinessEntityConverter.entityToJsonValue(dashboards); Ivy.var().set(PortalVariable.DASHBOARD.key, dashboardJson); - MenuView menuView = (MenuView) ManagedBeans.get("menuView"); menuView.updateDashboardCache(DashboardUtils.collectDashboards()); } diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/constant/IvyCacheIdentifier.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/constant/IvyCacheIdentifier.java index 6bcd5d20226..cc866d41c3c 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/constant/IvyCacheIdentifier.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/constant/IvyCacheIdentifier.java @@ -7,10 +7,11 @@ public final class IvyCacheIdentifier { public static final String LOGOUT_PAGE_CACHE_ENTRY_NAME = "LOGOUT_PAGE_ID"; public static final String STATISTIC_COLOR = "STATISTIC_COLOR"; public static final String ROLES_IN_SECURITY_CONTEXT = "ROLES_IN_SECURITY_CONTEXT"; - public static final String PORTAL_MENU = "PORTAL_MENU"; public static final String PORTAL_CUSTOM_MENU = "PORTAL_CUSTOM_MENU"; + public static final String PORTAL_DASHBOARDS = "PORTAL_DASHBOARDS"; public static final String PORTAL_PUBLIC_DASHBOARD = "PORTAL_PUBLIC_DASHBOARD"; public static final String PORTAL_PRIVATE_DASHBOARD = "PORTAL_PRIVATE_DASHBOARD"; + // for caching locales public static final String PORTAL_CONTENT_LOCALES = "PORTAL_CONTENT_LOCALES"; public static final String PORTAL_FORMATTING_LOCALES = "PORTAL_FORMATTING_LOCALES"; diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java index 08e87c70280..7fc57b2b588 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java @@ -7,7 +7,6 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.UUID; import java.util.function.Consumer; @@ -52,7 +51,6 @@ public class DashboardUtils { public final static String DEFAULT_CASE_LIST_DASHBOARD = "default-case-list-dashboard"; public static List getPublicDashboards() { - Locale requestLocale = Ivy.session().getContentLocale(); String sessionIdAttribute = SessionAttribute.SESSION_IDENTIFIER.toString(); if (Ivy.session().getAttribute(sessionIdAttribute) == null) { Ivy.session().setAttribute(sessionIdAttribute, UUID.randomUUID().toString()); @@ -67,7 +65,7 @@ public static List getPublicDashboards() { cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_PUBLIC_DASHBOARD, sessionUserId); } - if (portalPublicDashboardWrapper == null || !requestLocale.equals(portalPublicDashboardWrapper.loadedLocale)) { + if (portalPublicDashboardWrapper == null) { synchronized (PortalPublicDashboardWrapper.class) { List dashboards = new ArrayList<>(); try { @@ -78,7 +76,7 @@ public static List getPublicDashboards() { } catch (Exception e) { Ivy.log().error("Cannot load Public Dashboards {0}", e.getMessage()); } - portalPublicDashboardWrapper = new PortalPublicDashboardWrapper(requestLocale, dashboards); + portalPublicDashboardWrapper = new PortalPublicDashboardWrapper(dashboards); cacheService.setSessionCache(IvyCacheIdentifier.PORTAL_PUBLIC_DASHBOARD, sessionUserId, portalPublicDashboardWrapper); } @@ -87,7 +85,6 @@ public static List getPublicDashboards() { } public static List getPrivateDashboards() { - Locale requestLocale = Ivy.session().getContentLocale(); String sessionIdAttribute = SessionAttribute.SESSION_IDENTIFIER.toString(); if (Ivy.session().getAttribute(sessionIdAttribute) == null) { Ivy.session().setAttribute(sessionIdAttribute, UUID.randomUUID().toString()); @@ -102,7 +99,7 @@ public static List getPrivateDashboards() { cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_PRIVATE_DASHBOARD, sessionUserId); } - if (portalPrivateDashboardWrapper == null || !requestLocale.equals(portalPrivateDashboardWrapper.loadedLocale)) { + if (portalPrivateDashboardWrapper == null) { synchronized (PortalPublicDashboardWrapper.class) { List dashboards = new ArrayList<>(); try { @@ -111,7 +108,7 @@ public static List getPrivateDashboards() { } catch (Exception e) { Ivy.log().error("Cannot load Public Dashboards {0}", e.getMessage()); } - portalPrivateDashboardWrapper = new PortalPrivateDashboardWrapper(requestLocale, dashboards); + portalPrivateDashboardWrapper = new PortalPrivateDashboardWrapper(dashboards); cacheService.setSessionCache(IvyCacheIdentifier.PORTAL_PRIVATE_DASHBOARD, sessionUserId, portalPrivateDashboardWrapper); } @@ -317,9 +314,9 @@ public static void updatePropertiesToNullIfCurrentValueIsDefaultValue(List dashboards) { + private record PortalPrivateDashboardWrapper(List dashboards) { } - private record PortalPublicDashboardWrapper(Locale loadedLocale, List dashboards) { + private record PortalPublicDashboardWrapper(List dashboards) { } } From 09202c5769db9ab867fa3e92b361572fb36e94c1 Mon Sep 17 00:00:00 2001 From: nhthinh-axonivy Date: Tue, 17 Dec 2024 15:55:50 +0700 Subject: [PATCH 6/6] feature/IVYPORTAL-18050-Create-cache-mechanism-for-dashboard-converter-to-enhance-performance --- .../portal/src/ch/addon/portal/generic/menu/MenuView.java | 2 +- .../src/ch/ivy/addon/portalkit/util/DashboardUtils.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/MenuView.java b/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/MenuView.java index e56ded8a3a1..59f81315b5c 100644 --- a/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/MenuView.java +++ b/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/MenuView.java @@ -268,7 +268,7 @@ public PortalDashboardItemWrapper getDashboardCache() { } if (portalDashboardItemWrapper == null) { - synchronized (PortalDashboardItemWrapper.class) { + synchronized (this) { portalDashboardItemWrapper = new PortalDashboardItemWrapper(DashboardUtils.collectDashboards()); cacheService.setSessionCache(IvyCacheIdentifier.PORTAL_DASHBOARDS, sessionUserId, portalDashboardItemWrapper); } diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java index 7fc57b2b588..c8dd6cdf6b3 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java @@ -66,7 +66,7 @@ public static List getPublicDashboards() { } if (portalPublicDashboardWrapper == null) { - synchronized (PortalPublicDashboardWrapper.class) { + synchronized (sessionUserId.intern()) { List dashboards = new ArrayList<>(); try { String dashboardJson = Ivy.var().get(PortalVariable.DASHBOARD.key); @@ -100,7 +100,7 @@ public static List getPrivateDashboards() { } if (portalPrivateDashboardWrapper == null) { - synchronized (PortalPublicDashboardWrapper.class) { + synchronized (sessionUserId.intern()) { List dashboards = new ArrayList<>(); try { String dashboardInUserProperty = readDashboardBySessionUser();