From 2904535d40f3afdfa36e81877b410490b1ab3e23 Mon Sep 17 00:00:00 2001 From: Eva Vasques Date: Thu, 7 Nov 2024 18:03:52 +0000 Subject: [PATCH] MNT-24708 - Set messagesCache and loadedBundlesCache as local (#3026) * In a cluster env these caches were always invalidating the other nodes loaded bundles, forcing them to reload * Only resourceBundlesNamesCache should be invalidating to be able to force the cache reset if a bundle is added, removed or reloaded dynamically * On unregister of a resource bundle, the cache wasn't being explicitly updated, so it was not invalidating the cache on the other nodes. --- .../repo/i18n/MessageServiceImpl.java | 123 ++++++++++-------- .../main/resources/alfresco/caches.properties | 4 +- 2 files changed, 68 insertions(+), 59 deletions(-) diff --git a/repository/src/main/java/org/alfresco/repo/i18n/MessageServiceImpl.java b/repository/src/main/java/org/alfresco/repo/i18n/MessageServiceImpl.java index a18c24a41c..13863bdb7a 100644 --- a/repository/src/main/java/org/alfresco/repo/i18n/MessageServiceImpl.java +++ b/repository/src/main/java/org/alfresco/repo/i18n/MessageServiceImpl.java @@ -1,28 +1,28 @@ -/* - * #%L - * Alfresco Repository - * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - * #L% - */ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ package org.alfresco.repo.i18n; import java.io.BufferedReader; @@ -204,13 +204,11 @@ public class MessageServiceImpl implements MessageService { if (! tenantResourceBundleBaseNames.contains(resBundlePath)) { - tenantResourceBundleBaseNames.add(resBundlePath); - putResourceBundleBaseNames(tenantDomain, tenantResourceBundleBaseNames); + tenantResourceBundleBaseNames.add(resBundlePath); + reloadResourceBundles(tenantResourceBundleBaseNames); } logger.info("Registered message bundle '" + resBundlePath + "'"); - - clearLoadedResourceBundles(tenantDomain); // force re-load of message cache } finally { @@ -288,61 +286,64 @@ public class MessageServiceImpl implements MessageService Map> loadedResourceBundlesForAllLocales; Map> cachedMessagesForAllLocales; Set resourceBundleBaseNamesForAllLocales; - + String tenantDomain = getTenantDomain(); - LockHelper.tryLock(readLock, tryLockTimeout, "getting loaded resource bundles, messages and base names in 'MessageServiceImpl.unregisterResourceBundle()'"); + LockHelper.tryLock(readLock, tryLockTimeout, + "getting loaded resource bundles, messages and base names in 'MessageServiceImpl.unregisterResourceBundle()'"); try { // all locales loadedResourceBundlesForAllLocales = getLoadedResourceBundles(tenantDomain, false); cachedMessagesForAllLocales = getMessages(tenantDomain, false); resourceBundleBaseNamesForAllLocales = getResourceBundleBaseNames(tenantDomain, false, true); - } + } finally { readLock.unlock(); } - - LockHelper.tryLock(writeLock, tryLockTimeout, "removing resource bundle by path in 'MessageServiceImpl.unregisterResourceBundle()'"); + + LockHelper.tryLock(writeLock, tryLockTimeout, + "removing resource bundle by path in 'MessageServiceImpl.unregisterResourceBundle()'"); try { // unload resource bundles for each locale (by tenant, if applicable) if ((loadedResourceBundlesForAllLocales != null) && (cachedMessagesForAllLocales != null)) { Iterator itr = loadedResourceBundlesForAllLocales.keySet().iterator(); - + while (itr.hasNext()) - { + { Locale locale = itr.next(); - + Set loadedBundles = loadedResourceBundlesForAllLocales.get(locale); Map props = cachedMessagesForAllLocales.get(locale); - + if ((loadedBundles != null) && (props != null)) { if (loadedBundles.contains(resBundlePath)) { ResourceBundle resourcebundle = null; - + int idx1 = resBundlePath.indexOf(StoreRef.URI_FILLER); - + if (idx1 != -1) { // load from repository - int idx2 = resBundlePath.indexOf("/", idx1+3); - + int idx2 = resBundlePath.indexOf("/", idx1 + 3); + String store = resBundlePath.substring(0, idx2); String path = resBundlePath.substring(idx2); - + StoreRef storeRef = tenantService.getName(new StoreRef(store)); - + try { resourcebundle = getRepoResourceBundle(storeRef, path, locale); } catch (IOException ioe) { - throw new AlfrescoRuntimeException("Failed to read message resource bundle from repository " + resBundlePath + " : " + ioe); + throw new AlfrescoRuntimeException("Failed to read message resource bundle from repository " + + resBundlePath + " : " + ioe); } } else @@ -350,7 +351,7 @@ public class MessageServiceImpl implements MessageService // load from classpath resourcebundle = ResourceBundle.getBundle(resBundlePath, locale); } - + if (resourcebundle != null) { // unload from the cached messages @@ -361,21 +362,20 @@ public class MessageServiceImpl implements MessageService props.remove(key); } } - + loadedBundles.remove(resBundlePath); } } } } - + // unregister resource bundle if (resourceBundleBaseNamesForAllLocales != null) { resourceBundleBaseNamesForAllLocales.remove(resBundlePath); + reloadResourceBundles(resourceBundleBaseNamesForAllLocales); logger.info("Unregistered message bundle '" + resBundlePath + "'"); } - - clearLoadedResourceBundles(tenantDomain); // force re-load of message cache } finally { @@ -383,6 +383,14 @@ public class MessageServiceImpl implements MessageService } } + private void reloadResourceBundles(Set newResourceBundles) + { + logger.debug("Reloading message bundles ..."); + String tenantDomain = getTenantDomain(); + putResourceBundleBaseNames(tenantDomain, newResourceBundles); + clearLoadedResourceBundles(tenantDomain); // force re-load of message cache + } + /** * Get the messages for a locale. *

@@ -465,7 +473,7 @@ public class MessageServiceImpl implements MessageService Set resBundleBaseNames = getResourceBundleBaseNames(tenantDomain, true, false); int count = 0; - + // load resource bundles for given locale (by tenant, if applicable) for (String resBundlePath : resBundleBaseNames) { @@ -474,24 +482,25 @@ public class MessageServiceImpl implements MessageService ResourceBundle resourcebundle = null; int idx1 = resBundlePath.indexOf(StoreRef.URI_FILLER); - + if (idx1 != -1) { // load from repository - int idx2 = resBundlePath.indexOf("/", idx1+3); + int idx2 = resBundlePath.indexOf("/", idx1 + 3); String store = resBundlePath.substring(0, idx2); String path = resBundlePath.substring(idx2); StoreRef storeRef = tenantService.getName(new StoreRef(store)); - + try { resourcebundle = getRepoResourceBundle(storeRef, path, locale); } catch (IOException ioe) { - throw new AlfrescoRuntimeException("Failed to read message resource bundle from repository " + resBundlePath + " : " + ioe); + throw new AlfrescoRuntimeException( + "Failed to read message resource bundle from repository " + resBundlePath + " : " + ioe); } } else @@ -508,13 +517,13 @@ public class MessageServiceImpl implements MessageService String key = enumKeys.nextElement(); props.put(key, resourcebundle.getString(key)); } - + loadedBundles.add(resBundlePath); count++; } } } - + logger.info("Message bundles (x " + count + ") loaded for locale " + locale); } finally diff --git a/repository/src/main/resources/alfresco/caches.properties b/repository/src/main/resources/alfresco/caches.properties index 3d375e06ab..5b009d36b7 100644 --- a/repository/src/main/resources/alfresco/caches.properties +++ b/repository/src/main/resources/alfresco/caches.properties @@ -394,7 +394,7 @@ cache.loadedResourceBundlesSharedCache.tx.statsEnabled=${caches.tx.statsEnabled} cache.loadedResourceBundlesSharedCache.maxItems=1000 cache.loadedResourceBundlesSharedCache.timeToLiveSeconds=0 cache.loadedResourceBundlesSharedCache.maxIdleSeconds=0 -cache.loadedResourceBundlesSharedCache.cluster.type=invalidating +cache.loadedResourceBundlesSharedCache.cluster.type=local cache.loadedResourceBundlesSharedCache.backup-count=1 cache.loadedResourceBundlesSharedCache.eviction-policy=LRU cache.loadedResourceBundlesSharedCache.merge-policy=com.hazelcast.spi.merge.PutIfAbsentMergePolicy @@ -405,7 +405,7 @@ cache.messagesSharedCache.tx.statsEnabled=${caches.tx.statsEnabled} cache.messagesSharedCache.maxItems=1000 cache.messagesSharedCache.timeToLiveSeconds=0 cache.messagesSharedCache.maxIdleSeconds=0 -cache.messagesSharedCache.cluster.type=invalidating +cache.messagesSharedCache.cluster.type=local cache.messagesSharedCache.backup-count=1 cache.messagesSharedCache.eviction-policy=LRU cache.messagesSharedCache.merge-policy=com.hazelcast.spi.merge.PutIfAbsentMergePolicy