From 389abb488f6a7dd4295fa99fadb219662b21cfe6 Mon Sep 17 00:00:00 2001 From: erickgonzalez Date: Tue, 12 Dec 2023 10:27:15 -0600 Subject: [PATCH] #26931 include in 23.10.24 --- .../business/IdentifierCacheImplTest.java | 81 ++++++++++++++- .../business/IdentifierCache.java | 7 ++ .../business/IdentifierCacheImpl.java | 36 ++++++- .../business/VersionableFactoryImpl.java | 99 +++++++++---------- 4 files changed, 163 insertions(+), 60 deletions(-) diff --git a/dotCMS/src/integration-test/java/com/dotmarketing/business/IdentifierCacheImplTest.java b/dotCMS/src/integration-test/java/com/dotmarketing/business/IdentifierCacheImplTest.java index b91e4cfbe030..d5b694759565 100644 --- a/dotCMS/src/integration-test/java/com/dotmarketing/business/IdentifierCacheImplTest.java +++ b/dotCMS/src/integration-test/java/com/dotmarketing/business/IdentifierCacheImplTest.java @@ -1,8 +1,5 @@ package com.dotmarketing.business; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - import com.dotcms.datagen.LanguageDataGen; import com.dotcms.datagen.VariantDataGen; import com.dotcms.util.IntegrationTestInitService; @@ -14,6 +11,11 @@ import org.junit.BeforeClass; import org.junit.Test; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.*; + public class IdentifierCacheImplTest { @BeforeClass @@ -73,4 +75,77 @@ public void addIntoCacheWithVariant(){ assertNotNull(contentletVersionInfoFromCache); assertEquals(contentletVersionInfo, contentletVersionInfoFromCache); } + + /** + * Method to test: {@link IdentifierCacheImpl#putContentVersionInfos(String, List)} and {@link IdentifierCacheImpl#getContentVersionInfos(String)} + * When: Add a list of {@link ContentletVersionInfo} is added to cache + * Should: get it with {@link IdentifierCacheImpl#getContentVersionInfos(String)} + */ + @Test + public void putContentVersionInfos_and_getContentVersionInfos_successfully(){ + final String id = UUIDGenerator.generateUuid(); + final Language language1 = new LanguageDataGen().nextPersisted(); + final Language language2 = new LanguageDataGen().nextPersisted(); + final List listContentletVersionInfo = new ArrayList<>(); + + ContentletVersionInfo contentletVersionInfo = new ContentletVersionInfo(); + contentletVersionInfo.setIdentifier(id); + contentletVersionInfo.setLang(language1.getId()); + contentletVersionInfo.setVariant(VariantAPI.DEFAULT_VARIANT.name()); + listContentletVersionInfo.add(contentletVersionInfo); + + contentletVersionInfo = new ContentletVersionInfo(); + contentletVersionInfo.setIdentifier(id); + contentletVersionInfo.setLang(language2.getId()); + contentletVersionInfo.setVariant(VariantAPI.DEFAULT_VARIANT.name()); + listContentletVersionInfo.add(contentletVersionInfo); + + CacheLocator.getIdentifierCache().putContentVersionInfos(id,listContentletVersionInfo); + + final List listContentletVersionInfoFromCache = CacheLocator.getIdentifierCache() + .getContentVersionInfos(id); + + assertNotNull(listContentletVersionInfoFromCache); + assertEquals(listContentletVersionInfo.size(), listContentletVersionInfoFromCache.size()); + } + + + /** + * Method to test: {@link IdentifierCacheImpl#removeFromCacheByIdentifier(Identifier)} + * When: Add a list of {@link ContentletVersionInfo} is added to cache and removed by the identifier + * Should: all versions should be removed. + */ + @Test + public void removeFromCacheByIdentifier_successfully(){ + final String id = UUIDGenerator.generateUuid(); + final Language language1 = new LanguageDataGen().nextPersisted(); + final Language language2 = new LanguageDataGen().nextPersisted(); + final List listContentletVersionInfo = new ArrayList<>(); + + ContentletVersionInfo contentletVersionInfo = new ContentletVersionInfo(); + contentletVersionInfo.setIdentifier(id); + contentletVersionInfo.setLang(language1.getId()); + contentletVersionInfo.setVariant(VariantAPI.DEFAULT_VARIANT.name()); + listContentletVersionInfo.add(contentletVersionInfo); + + contentletVersionInfo = new ContentletVersionInfo(); + contentletVersionInfo.setIdentifier(id); + contentletVersionInfo.setLang(language2.getId()); + contentletVersionInfo.setVariant(VariantAPI.DEFAULT_VARIANT.name()); + listContentletVersionInfo.add(contentletVersionInfo); + + CacheLocator.getIdentifierCache().putContentVersionInfos(id,listContentletVersionInfo); + + List listContentletVersionInfoFromCache = CacheLocator.getIdentifierCache() + .getContentVersionInfos(id); + + assertNotNull(listContentletVersionInfoFromCache); + assertEquals(listContentletVersionInfo.size(), listContentletVersionInfoFromCache.size()); + + CacheLocator.getIdentifierCache().removeFromCacheByIdentifier(id); + + listContentletVersionInfoFromCache = CacheLocator.getIdentifierCache() + .getContentVersionInfos(id); + assertNull(listContentletVersionInfoFromCache); + } } diff --git a/dotCMS/src/main/java/com/dotmarketing/business/IdentifierCache.java b/dotCMS/src/main/java/com/dotmarketing/business/IdentifierCache.java index d73373257eb0..0d0322fb8485 100644 --- a/dotCMS/src/main/java/com/dotmarketing/business/IdentifierCache.java +++ b/dotCMS/src/main/java/com/dotmarketing/business/IdentifierCache.java @@ -5,6 +5,8 @@ import com.dotmarketing.beans.VersionInfo; import com.dotmarketing.portlets.contentlet.model.ContentletVersionInfo; +import java.util.List; + public abstract class IdentifierCache implements Cachable { abstract protected void addIdentifierToCache(Identifier id); @@ -70,4 +72,9 @@ public String get404Group() { return "Identifier404Cache"; } + public abstract void putContentVersionInfos(String identifier, + List cvis); + + public abstract List getContentVersionInfos(String identifier); + } diff --git a/dotCMS/src/main/java/com/dotmarketing/business/IdentifierCacheImpl.java b/dotCMS/src/main/java/com/dotmarketing/business/IdentifierCacheImpl.java index 5bb3b53c344d..673997eed7e2 100644 --- a/dotCMS/src/main/java/com/dotmarketing/business/IdentifierCacheImpl.java +++ b/dotCMS/src/main/java/com/dotmarketing/business/IdentifierCacheImpl.java @@ -11,11 +11,13 @@ import com.dotmarketing.beans.Host; import com.dotmarketing.beans.Identifier; import com.dotmarketing.beans.VersionInfo; +import com.dotmarketing.db.DbConnectionFactory; import com.dotmarketing.portlets.contentlet.model.ContentletVersionInfo; import com.dotmarketing.util.InodeUtils; import com.dotmarketing.util.Logger; import com.dotmarketing.util.UtilMethods; +import java.util.Collections; import java.util.List; /** @@ -159,15 +161,16 @@ protected void removeFromCacheByIdentifier(final Identifier id) { if(id==null) { return; } - - if(InodeUtils.isSet(id.getId())) { + + if(UtilMethods.isSet(id::getId)) { final String key = getPrimaryGroup() + id.getId(); cache.remove(key, getPrimaryGroup()); cache.remove(key, get404Group()); + cache.remove(allInfosKey(id.getId()), getVersionInfoGroup()); } final String uri = id.getURI(); - if(UtilMethods.isSet(id.getHostId()) && UtilMethods.isSet(uri)) { + if(UtilMethods.isSet(id::getHostId) && UtilMethods.isSet(uri)) { final String key = getPrimaryGroup() + id.getHostId() + "-" + uri; cache.remove(key, getPrimaryGroup()); cache.remove(key, get404Group()); @@ -226,6 +229,7 @@ public void removeFromCacheByVersionable(Versionable versionable) { public void removeFromCacheByInode(String inode) { cache.remove(getVersionGroup() + inode, getVersionGroup()); + cache.remove(allInfosKey(inode), getVersionInfoGroup()); } @@ -295,16 +299,42 @@ public VersionInfo getVersionInfo(String identifier) { public void removeContentletVersionInfoToCache(String identifier, long lang) { String key = getKey(identifier, lang); cache.remove(getVersionInfoGroup()+key, getVersionInfoGroup()); + cache.remove(allInfosKey(identifier), getVersionInfoGroup()); } @Override public void removeContentletVersionInfoToCache(String identifier, long lang, final String variantId) { String key = getKey(identifier, lang, variantId); cache.remove(getVersionInfoGroup() + key , getVersionInfoGroup()); + cache.remove(allInfosKey(identifier), getVersionInfoGroup()); } @Override protected void removeVersionInfoFromCache(String identifier) { cache.remove(getVersionInfoGroup()+identifier, getVersionInfoGroup()); + cache.remove(allInfosKey(identifier), getVersionInfoGroup()); } + + private String allInfosKey(String... vals){ + return "all-"+ String.join("-", vals); + } + + + @Override + public List getContentVersionInfos(final String identifier){ + // we don't read from cache in transactions + if(DbConnectionFactory.inTransaction()){ + return Collections.emptyList(); + } + return (List) cache.getNoThrow(allInfosKey(identifier) , getVersionInfoGroup()); + } + + @Override + public void putContentVersionInfos(final String identifier, final List versionInfos){ + // we don't write cache in transactions + if(DbConnectionFactory.inTransaction()){ + return; + } + cache.put(allInfosKey(identifier) ,versionInfos, getVersionInfoGroup()); + } } diff --git a/dotCMS/src/main/java/com/dotmarketing/business/VersionableFactoryImpl.java b/dotCMS/src/main/java/com/dotmarketing/business/VersionableFactoryImpl.java index f86f235a083a..ad9e860ab438 100644 --- a/dotCMS/src/main/java/com/dotmarketing/business/VersionableFactoryImpl.java +++ b/dotCMS/src/main/java/com/dotmarketing/business/VersionableFactoryImpl.java @@ -14,6 +14,7 @@ import com.dotmarketing.db.DbConnectionFactory; import com.dotmarketing.db.HibernateUtil; import com.dotmarketing.exception.DotDataException; +import com.dotmarketing.exception.DotRuntimeException; import com.dotmarketing.exception.DotSecurityException; import com.dotmarketing.portlets.containers.business.ContainerAPI; import com.dotmarketing.portlets.containers.model.Container; @@ -32,6 +33,8 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; + import org.apache.commons.beanutils.BeanUtils; /** @@ -390,56 +393,20 @@ public Optional findAnyContentletVersionInfo(final String @Override public Optional findAnyContentletVersionInfo(final String identifier, final boolean deleted) throws DotDataException { - final DotConnect dotConnect = new DotConnect() - .setSQL("SELECT * FROM contentlet_version_info WHERE identifier= ? AND deleted = ? " - + "AND variant_id = '"+DEFAULT_VARIANT.name()+"'") - .addParam(identifier) - .addParam(deleted) - .setMaxRows(1); - - final List versionInfos = TransformerLocator - .createContentletVersionInfoTransformer(dotConnect.loadObjectResults()).asList(); - - return versionInfos == null || versionInfos.isEmpty() - ? Optional.empty() - : Optional.of(versionInfos.get(0)); + return findContentletVersionInfos(identifier, DEFAULT_VARIANT.name(), 0).stream().filter(cvi->!cvi.isDeleted() || deleted ).findAny(); } @Override public Optional findAnyContentletVersionInfoAnyVariant(final String identifier, final boolean deleted) throws DotDataException { - final DotConnect dotConnect = new DotConnect() - .setSQL("SELECT * FROM contentlet_version_info WHERE identifier= ? AND deleted = ?") - .addParam(identifier) - .addParam(deleted) - .setMaxRows(1); - - final List versionInfos = TransformerLocator - .createContentletVersionInfoTransformer(dotConnect.loadObjectResults()).asList(); - - return versionInfos == null || versionInfos.isEmpty() - ? Optional.empty() - : Optional.of(versionInfos.get(0)); + return findContentletVersionInfos(identifier, null, 0).stream().filter(cvi->!cvi.isDeleted() || deleted ).findAny(); } @Override public Optional findAnyContentletVersionInfo(final String identifier, final String variant, final boolean deleted) throws DotDataException { - final DotConnect dotConnect = new DotConnect() - .setSQL("SELECT * FROM contentlet_version_info WHERE identifier= ? AND deleted = ? " - + "AND variant_id = ?") - .addParam(identifier) - .addParam(deleted) - .addParam(variant) - .setMaxRows(1); - - final List versionInfos = TransformerLocator - .createContentletVersionInfoTransformer(dotConnect.loadObjectResults()).asList(); - - return versionInfos == null || versionInfos.isEmpty() - ? Optional.empty() - : Optional.of(versionInfos.get(0)); + return findContentletVersionInfos(identifier, variant, 0).stream().filter(cvi->!cvi.isDeleted() || deleted ).findAny(); } private List findContentletVersionInfos(final String identifier, @@ -448,38 +415,62 @@ private List findContentletVersionInfos(final String iden } private List findContentletVersionInfos(final String identifier, final String variantName, - final int maxResults) throws DotDataException, DotStateException { - final DotConnect dotConnect = new DotConnect(); + final int maxResults) throws DotDataException, DotStateException { + List infos = findAllContentletVersionInfos(identifier); if (UtilMethods.isSet(variantName)) { - dotConnect.setSQL( - "SELECT * FROM contentlet_version_info WHERE identifier=? AND variant_id = ?") - .addParam(identifier) - .addParam(variantName); - } else { - dotConnect.setSQL( - "SELECT * FROM contentlet_version_info WHERE identifier=?") - .addParam(identifier); + infos = infos.stream().filter(i-> variantName.equals(i.getVariant())).collect(Collectors.toList()); } - if (maxResults > 0) { - dotConnect.setMaxRows(maxResults); + if (maxResults > 0 && infos.size() > maxResults) { + infos = infos.subList(0, maxResults); } + return infos; + + } + + /** + * this will return ALL CVIs from the database + * @param identifier + * @return + * @throws DotDataException + * @throws DotStateException + */ + private List findContentletVersionInfosInDB(final String identifier) throws DotDataException, DotStateException { + + DotConnect dotConnect = new DotConnect().setSQL( + "SELECT * FROM contentlet_version_info WHERE identifier=?") + .addParam(identifier); final List versionInfos = TransformerLocator .createContentletVersionInfoTransformer(dotConnect.loadObjectResults()).asList(); - return versionInfos == null || versionInfos.isEmpty() ? Collections.emptyList() : versionInfos; } - @Override protected List findAllContentletVersionInfos(final String identifier) throws DotDataException, DotStateException { - return findContentletVersionInfos(identifier, -1); + if(identifier==null){ + throw new DotRuntimeException("identifier cannot be null"); + } + + List infos = icache.getContentVersionInfos(identifier); + if (infos != null) { + return infos; + } + synchronized (identifier.intern()) { + infos = icache.getContentVersionInfos(identifier); + if (infos != null) { + return infos; + } + infos = findContentletVersionInfosInDB(identifier); + icache.putContentVersionInfos(identifier, infos); + return infos; + } } + @Override protected List findAllContentletVersionInfos(final String identifier, final String variantName) throws DotDataException, DotStateException {