From ce9fcce2818ea1e4d94e254230db090d2a8e02f8 Mon Sep 17 00:00:00 2001 From: nhthinh-axonivy Date: Tue, 24 Dec 2024 17:22:23 +0700 Subject: [PATCH 1/2] IVYPORTAL-18050-Create-cache-mechanism-for-dashboard-converter-to-enhance-performance-ver2 _ refactor current cache _ introduce new cache _ unify collect dashboard to DashboardUtils --- .../addon/portal/generic/menu/MenuView.java | 56 +---- .../generic/menu/PortalMenuNavigator.java | 38 +--- .../portal/generic/bean/DashboardBean.java | 32 --- .../bean/DashboardDetailModificationBean.java | 11 +- .../bean/DashboardModificationBean.java | 21 +- .../bean/DashboardWelcomeWidgetBean.java | 5 +- .../constant/IvyCacheIdentifier.java | 2 + .../portalkit/dto/dashboard/Dashboard.java | 2 +- .../addon/portalkit/util/DashboardUtils.java | 197 +++++++++++++----- 9 files changed, 163 insertions(+), 201 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 25dc3cf939d..c532fd7c412 100644 --- a/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/MenuView.java +++ b/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/MenuView.java @@ -13,7 +13,6 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.UUID; import javax.faces.bean.ManagedBean; import javax.faces.bean.ViewScoped; @@ -37,14 +36,11 @@ import ch.addon.portal.generic.userprofile.homepage.HomepageUtils; import ch.ivy.addon.portal.generic.navigation.PortalNavigator; 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.ApplicationMultiLanguage; -import ch.ivy.addon.portalkit.service.IvyCacheService; import ch.ivy.addon.portalkit.service.MainMenuEntryService; import ch.ivy.addon.portalkit.util.DashboardUtils; import ch.ivy.addon.portalkit.util.UrlUtils; @@ -159,7 +155,7 @@ private MenuElement buildDashboardItem() { String localizedTitle = getLocalizedTitle(dashboard, currentLanguage, dashboardTitle); return buildSingleDashboardMenu(localizedTitle, dashboardId, dashboardLink, dashboard.getIcon()); } - + return buildSingleDashboardMenu(dashboardTitle, "", dashboardLink, ""); } @@ -175,8 +171,7 @@ private String determineDashboardLink() { } private List getSubItemDashboards() { - var dashboards = getDashboardCache().dashboards; - return dashboards.stream().filter(dashboard -> !dashboard.getIsTopMenu()).toList(); + return DashboardUtils.getDashboardsWithoutMenuItem(); } private MenuElement buildDashboardGroupMenu(List subItemDashboards, String defaultTitle, @@ -256,50 +251,6 @@ 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_MENU, sessionUserId); - } - - private String getSessionUserId() { - String sessionIdAttribute = SessionAttribute.SESSION_IDENTIFIER.name(); - if (session().getAttribute(sessionIdAttribute) == null) { - session().setAttribute(sessionIdAttribute, UUID.randomUUID().toString()); - } - 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(); } @@ -522,9 +473,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 f627e684967..6776e03766a 100644 --- a/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/PortalMenuNavigator.java +++ b/AxonIvyPortal/portal/src/ch/addon/portal/generic/menu/PortalMenuNavigator.java @@ -9,9 +9,7 @@ import java.util.ArrayList; import java.util.Collections; 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 +26,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 +106,7 @@ 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 getSubmenuList(); } public static void navigateToTargetPage(boolean isClickOnBreadcrumb, String destinationPage, @@ -156,9 +123,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 1a1ea137112..e5946f3fbb2 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,8 +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.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 +53,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; @@ -91,11 +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()) || isRequestPathForMainOrDetailModification()) { updateSelectedDashboardIdFromSessionAttribute(); @@ -156,18 +147,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); } @@ -185,17 +164,6 @@ protected void buildWidgetModels(Dashboard dashboard) { } } - protected List getVisiblePublicDashboards() { - String dashboardJson = Ivy.var().get(PortalVariable.DASHBOARD.key); - List visibleDashboards = DashboardUtils.getVisibleDashboards(dashboardJson); - setDashboardAsPublic(visibleDashboards); - 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..d8d6ea2f485 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,8 +176,7 @@ 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); @@ -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..abf373c8866 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 @@ -33,7 +33,6 @@ import com.axonivy.portal.service.DeepLTranslationService; import com.axonivy.portal.util.WelcomeWidgetUtils; -import ch.addon.portal.generic.menu.MenuView; import ch.ivy.addon.portal.generic.navigation.PortalNavigator; import ch.ivy.addon.portalkit.dto.DisplayName; import ch.ivy.addon.portalkit.dto.dashboard.Dashboard; @@ -41,7 +40,6 @@ import ch.ivy.addon.portalkit.dto.dashboard.WelcomeDashboardWidget; import ch.ivy.addon.portalkit.enums.PortalVariable; import ch.ivy.addon.portalkit.ivydata.mapper.SecurityMemberDTOMapper; -import ch.ivy.addon.portalkit.jsf.ManagedBeans; import ch.ivy.addon.portalkit.persistence.converter.BusinessEntityConverter; import ch.ivy.addon.portalkit.util.DashboardUtils; import ch.ivy.addon.portalkit.util.PermissionUtils; @@ -74,7 +72,7 @@ protected void collectDashboardsForManagement() { this.dashboards = DashboardUtils.getPublicDashboards(); DashboardUtils.addDefaultTaskCaseListDashboardsIfMissing(this.dashboards); } else if (StringUtils.isNoneEmpty(dashboardInUserProperty)) { - List myDashboards = getVisibleDashboards(dashboardInUserProperty); + List myDashboards = DashboardUtils.getPrivateDashboards(); this.dashboards.addAll(myDashboards); } } @@ -176,17 +174,7 @@ private void saveDashboards(List dashboards) { } else { currentUser().setProperty(PortalVariable.DASHBOARD.key, dashboardJson); } - - MenuView menuView = (MenuView) ManagedBeans.get("menuView"); - menuView.updateDashboardCache(DashboardUtils.collectDashboards()); - } - - private List getVisibleDashboards(String dashboardJson) { - if (isPublicDashboard) { - return DashboardUtils.jsonToDashboards(dashboardJson); - } else { - return DashboardUtils.getVisibleDashboards(dashboardJson); - } + updateDashboardCache(); } public void navigateToDashboardDetailsPage(String dashboardId) { @@ -388,6 +376,7 @@ public void saveArrangment() { } else { savePrivateArrangement(); } + updateDashboardCache(); } public void savePublicArrangement() { @@ -414,4 +403,8 @@ public void savePrivateArrangement() { String dashboardJson = BusinessEntityConverter.entityToJsonValue(this.dashboards); Ivy.session().getSessionUser().setProperty(PortalVariable.DASHBOARD.key, dashboardJson); } + + private void updateDashboardCache() { + DashboardUtils.updateDashboardCache(); + } } 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..e1b78ec2ced 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/bean/DashboardWelcomeWidgetBean.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/bean/DashboardWelcomeWidgetBean.java @@ -15,7 +15,6 @@ import com.axonivy.portal.util.WelcomeWidgetUtils; -import ch.addon.portal.generic.menu.MenuView; import ch.ivy.addon.portalkit.dto.DisplayName; import ch.ivy.addon.portalkit.dto.dashboard.Dashboard; import ch.ivy.addon.portalkit.dto.dashboard.WelcomeDashboardWidget; @@ -23,7 +22,6 @@ import ch.ivy.addon.portalkit.enums.PortalVariable; import ch.ivy.addon.portalkit.enums.WelcomeTextPosition; import ch.ivy.addon.portalkit.jsf.Attrs; -import ch.ivy.addon.portalkit.jsf.ManagedBeans; import ch.ivy.addon.portalkit.persistence.converter.BusinessEntityConverter; import ch.ivy.addon.portalkit.support.HtmlParser; import ch.ivy.addon.portalkit.util.DashboardUtils; @@ -97,8 +95,7 @@ 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()); + DashboardUtils.updateDashboardCache(); } } 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..ca296d5734e 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,8 @@ 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_PRIVATE_DASHBOARDS = "PORTAL_PRIVATE_DASHBOARDS"; + public static final String PORTAL_PUBLIC_DASHBOARDS = "PORTAL_PUBLIC_DASHBOARDS"; // for caching locales public static final String PORTAL_CONTENT_LOCALES = "PORTAL_CONTENT_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 234df2d8057..e5a5ac12c77 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 @@ -144,7 +144,7 @@ public void setTemplateId(String templateId) { } public Boolean getIsTopMenu() { - return isTopMenu; + return isTopMenu == null ? false : 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 5a66ea4269e..030519c61bf 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java @@ -22,7 +22,6 @@ 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; @@ -35,6 +34,7 @@ import ch.ivyteam.ivy.environment.Ivy; import ch.ivyteam.ivy.security.ISecurityConstants; import ch.ivyteam.ivy.security.IUser; +import ch.ivyteam.ivy.workflow.IWorkflowSession; public class DashboardUtils { @@ -42,7 +42,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 = @@ -113,32 +114,17 @@ private static IUser currentUser() { public static List getAllVisibleDashboardsOfSessionUser() { List collectedDashboards = new ArrayList<>(); - String dashboardInUserProperty = readDashboardBySessionUser(); try { - collectedDashboards.addAll(getVisiblePublicDashboards()); - collectedDashboards.addAll(jsonToDashboards(dashboardInUserProperty)); + collectedDashboards.addAll(getPublicDashboards()); + collectedDashboards.addAll(getPrivateDashboards()); } catch (PortalException e) { // If errors like parsing JSON errors, ignore them Ivy.log().error(e); } + Ivy.log().error(collectedDashboards.size()); 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) { if (!hasDashboardWithId(dashboards, DEFAULT_CASE_LIST_DASHBOARD)) { dashboards.add(0, DefaultDashboardUtils.getDefaultCaseListDashboard()); @@ -183,25 +169,6 @@ private static String readDashboardBySessionUser() { return currentUser().getProperty(PortalVariable.DASHBOARD.key); } - 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); - } - } - collectedDashboards.addAll(idToDashboard.values()); - addDefaultTaskCaseListDashboardsIfMissing(collectedDashboards); - return collectedDashboards; - } - public static List collectMainDashboards() { List collectedDashboards = new ArrayList<>(getPublicDashboards().stream().filter(dashboard -> dashboard.getIsTopMenu()).toList()); @@ -287,8 +254,7 @@ public static void storeDashboardInSession(String id, boolean isMainDashboard) { } public static List getDashboardsWithoutMenuItem() { - var dashboards = collectDashboards(); - return dashboards.stream().filter(dashboard -> !dashboard.getIsTopMenu()).toList(); + return collectDashboards().stream().filter(dashboard -> !dashboard.getIsTopMenu()).toList(); } public static String getSelectedMainDashboardIdFromSession() { @@ -305,10 +271,9 @@ public static boolean isMainDashboard(String dashboardId, boolean defaultValue) if (StringUtils.isEmpty(dashboardId)) { return false; } - 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); + 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; } @@ -328,12 +293,146 @@ public static void updatePropertiesToNullIfCurrentValueIsDefaultValue(List "").contentEquals(DEFAULT_TASK_LIST_DASHBOARD); + return Optional.ofNullable(dashboard).map(Dashboard::getId).orElseGet(() -> "") + .contentEquals(DEFAULT_TASK_LIST_DASHBOARD); } public static boolean isDefaultCaseListDashboard(Dashboard dashboard) { - return Optional.ofNullable(dashboard).map(Dashboard::getId) - .orElseGet(() -> "").contentEquals(DEFAULT_CASE_LIST_DASHBOARD); + return Optional.ofNullable(dashboard).map(Dashboard::getId).orElseGet(() -> "") + .contentEquals(DEFAULT_CASE_LIST_DASHBOARD); + } + + public static List getPublicDashboards() { + 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_DASHBOARDS, sessionUserId).orElse(null); + } catch (ClassCastException e) { + cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_PUBLIC_DASHBOARDS, sessionUserId); + } + + if (portalPublicDashboardWrapper == null) { + synchronized (sessionUserId.intern()) { + List dashboards = new ArrayList<>(); + try { + String dashboardJson = Ivy.var().get(PortalVariable.DASHBOARD.key); + dashboards = jsonToDashboards(dashboardJson); + addDefaultTaskCaseListDashboardsIfMissing(dashboards); + setDashboardAsPublic(dashboards); + } catch (Exception e) { + Ivy.log().error("Cannot load Public Dashboards {0}", e.getMessage()); + } + portalPublicDashboardWrapper = new PortalPublicDashboardWrapper(dashboards); + cacheService.setSessionCache(IvyCacheIdentifier.PORTAL_PUBLIC_DASHBOARDS, sessionUserId, + portalPublicDashboardWrapper); + } + } + return portalPublicDashboardWrapper.dashboards(); + } + + public static List getPrivateDashboards() { + 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_DASHBOARDS, sessionUserId).orElse(null); + } catch (ClassCastException e) { + cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_PRIVATE_DASHBOARDS, sessionUserId); + } + + if (portalPrivateDashboardWrapper == null) { + synchronized (sessionUserId.intern()) { + 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(dashboards); + cacheService.setSessionCache(IvyCacheIdentifier.PORTAL_PRIVATE_DASHBOARDS, sessionUserId, + portalPrivateDashboardWrapper); + } + } + return portalPrivateDashboardWrapper.dashboards(); + } + + public static List collectDashboards() { + String sessionUserId = getSessionUserId(); + IvyCacheService cacheService = IvyCacheService.getInstance(); + PortalDashboardItemWrapper portalDashboardItemWrapper = null; + try { + portalDashboardItemWrapper = (PortalDashboardItemWrapper) cacheService + .getSessionCacheValue(IvyCacheIdentifier.PORTAL_DASHBOARDS, sessionUserId).orElse(null); + } catch (ClassCastException e) { + cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_DASHBOARDS, sessionUserId); + } + + if (portalDashboardItemWrapper == null) { + synchronized (sessionUserId.intern()) { + List collectedDashboards = new ArrayList<>(); + try { + List visibleDashboards = getAllVisibleDashboardsOfSessionUser(); + List dashboardOrders = getDashboardOrdersOfSessionUser(); + Map idToDashboard = createMapIdToDashboard(visibleDashboards); + 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); + } catch (Exception e) { + Ivy.log().error("Cannot collect Dashboards {0}", e.getMessage()); + } + portalDashboardItemWrapper = new PortalDashboardItemWrapper(collectedDashboards); + cacheService.setSessionCache(IvyCacheIdentifier.PORTAL_DASHBOARDS, sessionUserId, + portalDashboardItemWrapper); + } + } + return portalDashboardItemWrapper.dashboards; } + + public static void updateDashboardCache() { + String sessionUserId = getSessionUserId(); + IvyCacheService cacheService = IvyCacheService.getInstance(); + cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_DASHBOARDS, sessionUserId); + cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_PRIVATE_DASHBOARDS, sessionUserId); + cacheService.invalidateSessionEntry(IvyCacheIdentifier.PORTAL_PRIVATE_DASHBOARDS, sessionUserId); + } + + private static String getSessionUserId() { + String sessionIdAttribute = SessionAttribute.SESSION_IDENTIFIER.name(); + if (session().getAttribute(sessionIdAttribute) == null) { + session().setAttribute(sessionIdAttribute, UUID.randomUUID().toString()); + } + return (String) session().getAttribute(sessionIdAttribute); + } + + private static IWorkflowSession session() { + return Ivy.session(); + } + + private record PortalPrivateDashboardWrapper(List dashboards) { + } + private record PortalPublicDashboardWrapper(List dashboards) { + } + public record PortalDashboardItemWrapper(List dashboards) { + } + } From 7d612926fa79a3496269fc2beb2598afcbf122db Mon Sep 17 00:00:00 2001 From: nhthinh-axonivy Date: Wed, 25 Dec 2024 09:28:34 +0700 Subject: [PATCH 2/2] IVYPORTAL-18050-Create-cache-mechanism-for-dashboard-converter-to-enhance-performance-ver2 --- .../portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java | 1 - 1 file changed, 1 deletion(-) 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 030519c61bf..445408587a6 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardUtils.java @@ -121,7 +121,6 @@ public static List getAllVisibleDashboardsOfSessionUser() { // If errors like parsing JSON errors, ignore them Ivy.log().error(e); } - Ivy.log().error(collectedDashboards.size()); return collectedDashboards; }