From fd6c651ece18acf5ab4c761fd525a6c2fa2e8792 Mon Sep 17 00:00:00 2001 From: Tiago Salvado <9038083+tiagosalvado10@users.noreply.github.com> Date: Fri, 28 Mar 2025 23:17:58 +0000 Subject: [PATCH] [MNT-24992] Add method to force renditions content hash code (#3288) (cherry picked from commit 74380693d086fc99bd00f128f78e206725bc9780) --- .secrets.baseline | 4 +- .../repo/rendition2/RenditionService2.java | 11 +++- .../rendition2/RenditionService2Impl.java | 33 ++++++++++- .../AbstractRenditionIntegrationTest.java | 29 +++++++++- .../RenditionService2IntegrationTest.java | 57 ++++++++++++++++++- 5 files changed, 128 insertions(+), 6 deletions(-) diff --git a/.secrets.baseline b/.secrets.baseline index 42456c42ab..e5c3a4dc72 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -1539,7 +1539,7 @@ "filename": "repository/src/test/java/org/alfresco/repo/rendition2/AbstractRenditionIntegrationTest.java", "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", "is_verified": false, - "line_number": 127, + "line_number": 130, "is_secret": false } ], @@ -1888,5 +1888,5 @@ } ] }, - "generated_at": "2024-10-09T09:32:52Z" + "generated_at": "2025-03-27T23:45:41Z" } \ No newline at end of file diff --git a/repository/src/main/java/org/alfresco/repo/rendition2/RenditionService2.java b/repository/src/main/java/org/alfresco/repo/rendition2/RenditionService2.java index bd7d4c3b7f..da0674bddb 100644 --- a/repository/src/main/java/org/alfresco/repo/rendition2/RenditionService2.java +++ b/repository/src/main/java/org/alfresco/repo/rendition2/RenditionService2.java @@ -2,7 +2,7 @@ * #%L * Alfresco Repository * %% - * Copyright (C) 2005 - 2022 Alfresco Software Limited + * Copyright (C) 2005 - 2025 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -124,4 +124,13 @@ public interface RenditionService2 * Indicates if renditions are enabled. Set using the {@code system.thumbnail.generate} value. */ boolean isEnabled(); + + /** + * This method forces the content hash code for every {@code sourceNodeRef} renditions. + * + * @param sourceNodeRef + * the source node to update renditions hash code + */ + @NotAuditable + void forceRenditionsContentHashCode(NodeRef sourceNodeRef); } \ No newline at end of file diff --git a/repository/src/main/java/org/alfresco/repo/rendition2/RenditionService2Impl.java b/repository/src/main/java/org/alfresco/repo/rendition2/RenditionService2Impl.java index 4de95b295c..b6cc9109dd 100644 --- a/repository/src/main/java/org/alfresco/repo/rendition2/RenditionService2Impl.java +++ b/repository/src/main/java/org/alfresco/repo/rendition2/RenditionService2Impl.java @@ -2,7 +2,7 @@ * #%L * Alfresco Repository * %% - * Copyright (C) 2005 - 2022 Alfresco Software Limited + * Copyright (C) 2005 - 2025 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -950,4 +950,35 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea } } + @Override + public void forceRenditionsContentHashCode(NodeRef sourceNodeRef) + { + if (sourceNodeRef != null && nodeService.exists(sourceNodeRef)) + { + List renditions = getRenditionChildAssociations(sourceNodeRef); + if (renditions != null) + { + int sourceContentHashCode = getSourceContentHashCode(sourceNodeRef); + for (ChildAssociationRef rendition : renditions) + { + NodeRef renditionNode = rendition.getChildRef(); + if (nodeService.hasAspect(renditionNode, RenditionModel.ASPECT_RENDITION2)) + { + int renditionContentHashCode = getRenditionContentHashCode(renditionNode); + String renditionName = rendition.getQName().getLocalName(); + if (sourceContentHashCode != renditionContentHashCode) + { + if (logger.isDebugEnabled()) + { + logger.debug("Update content hash code for rendition " + renditionName + " of node " + + sourceNodeRef); + } + nodeService.setProperty(renditionNode, PROP_RENDITION_CONTENT_HASH_CODE, + sourceContentHashCode); + } + } + } + } + } + } } diff --git a/repository/src/test/java/org/alfresco/repo/rendition2/AbstractRenditionIntegrationTest.java b/repository/src/test/java/org/alfresco/repo/rendition2/AbstractRenditionIntegrationTest.java index 2b8826659c..2af79b1fd6 100644 --- a/repository/src/test/java/org/alfresco/repo/rendition2/AbstractRenditionIntegrationTest.java +++ b/repository/src/test/java/org/alfresco/repo/rendition2/AbstractRenditionIntegrationTest.java @@ -2,7 +2,7 @@ * #%L * Alfresco Repository * %% - * Copyright (C) 2005 - 2022 Alfresco Software Limited + * Copyright (C) 2005 - 2025 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -45,6 +45,7 @@ import org.alfresco.repo.thumbnail.ThumbnailRegistry; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.service.cmr.rendition.RenditionService; import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentWriter; @@ -52,6 +53,7 @@ import org.alfresco.service.cmr.repository.MimetypeService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.security.MutableAuthenticationService; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PersonService; @@ -128,6 +130,7 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest protected static final String ADMIN = "admin"; protected static final String DOC_LIB = "doclib"; + protected static final String PDF = "pdf"; private CronExpression origLocalTransCron; private CronExpression origRenditionCron; @@ -569,4 +572,28 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest return renditionContentHashCode; } + + /** + * Helper method which gets the content hash code from the supplied source node (the equivalent method from {@link RenditionService2Impl} is not public) + * + * @param sourceNodeRef + * the source node + * + * @return -1 in case of there is no content, otherwise, the actual content hash code otherwise + */ + protected int getSourceContentHashCode(NodeRef sourceNodeRef) + { + int hashCode = -1; + ContentData contentData = DefaultTypeConverter.INSTANCE.convert(ContentData.class, nodeService.getProperty(sourceNodeRef, PROP_CONTENT)); + if (contentData != null) + { + // Originally we used the contentData URL, but that is not enough if the mimetype changes. + String contentString = contentData.getContentUrl() + contentData.getMimetype(); + if (contentString != null) + { + hashCode = contentString.hashCode(); + } + } + return hashCode; + } } diff --git a/repository/src/test/java/org/alfresco/repo/rendition2/RenditionService2IntegrationTest.java b/repository/src/test/java/org/alfresco/repo/rendition2/RenditionService2IntegrationTest.java index ec72dcfbb5..7a70722778 100644 --- a/repository/src/test/java/org/alfresco/repo/rendition2/RenditionService2IntegrationTest.java +++ b/repository/src/test/java/org/alfresco/repo/rendition2/RenditionService2IntegrationTest.java @@ -2,7 +2,7 @@ * #%L * Alfresco Repository * %% - * Copyright (C) 2005 - 2022 Alfresco Software Limited + * Copyright (C) 2005 - 2025 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -455,6 +455,61 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati assertEquals(TOTAL_NODES, countModifier(nodes, user1)); } + @Test + public void testForceRenditionsContentHashCode() + { + + // Create a node + NodeRef sourceNodeRef = createSource(ADMIN, "quick.docx"); + assertNotNull("Node not generated", sourceNodeRef); + + // Get content hash code for the source node + int sourceNodeContentHashCode = getSourceContentHashCode(sourceNodeRef); + + // Trigger the pdf rendition + render(ADMIN, sourceNodeRef, PDF); + NodeRef pdfRenditionNodeRef = waitForRendition(ADMIN, sourceNodeRef, PDF, true); + assertNotNull("pdf rendition was not generated", pdfRenditionNodeRef); + assertNotNull("pdf rendition was not generated", nodeService.getProperty(pdfRenditionNodeRef, PROP_CONTENT)); + + // Check the pdf rendition content hash code is valid + int pdfRenditionContentHashCode = getRenditionContentHashCode(pdfRenditionNodeRef); + assertEquals("pdf rendition content hash code is different from source node content hash code", sourceNodeContentHashCode, pdfRenditionContentHashCode); + + // Trigger the doc lib rendition + render(ADMIN, sourceNodeRef, DOC_LIB); + NodeRef docLibRenditionNodeRef = waitForRendition(ADMIN, sourceNodeRef, DOC_LIB, true); + assertNotNull("doc lib rendition was not generated", docLibRenditionNodeRef); + assertNotNull("doc lib rendition was not generated", nodeService.getProperty(docLibRenditionNodeRef, PROP_CONTENT)); + + // Check the doc lib rendition content hash code is valid + int docLibenditionContentHashCode = getRenditionContentHashCode(docLibRenditionNodeRef); + assertEquals("doc lib rendition content hash code is different from source node content hash code", sourceNodeContentHashCode, docLibenditionContentHashCode); + + // Update the source node content + updateContent(ADMIN, sourceNodeRef, "quick.docx"); + + // Get source node content hash code after update + int sourceNodeContentHashCode2 = getSourceContentHashCode(sourceNodeRef); + + // Check content hash code are different after content update + assertNotEquals("Source node content hash code is the same after content update", sourceNodeContentHashCode, sourceNodeContentHashCode2); + assertNotEquals("pdf rendition content hash code is the same after content update", sourceNodeContentHashCode2, pdfRenditionContentHashCode); + assertNotEquals("doc lib rendition content hash code is the same after content update", sourceNodeContentHashCode2, docLibenditionContentHashCode); + + // Forces the content hash code for every source node renditions + AuthenticationUtil.runAs(() -> { + renditionService2.forceRenditionsContentHashCode(sourceNodeRef); + return null; + }, ADMIN); + + // Check the renditions content hash code are now the same as the latest source node content hash code + int pdfRenditionContentHashCode2 = getRenditionContentHashCode(pdfRenditionNodeRef); + int docLibenditionContentHashCode2 = getRenditionContentHashCode(docLibRenditionNodeRef); + assertEquals("pdf rendition content hash code is different from latest source node content hash code", sourceNodeContentHashCode2, pdfRenditionContentHashCode2); + assertEquals("doc lib rendition content hash code is different from latest source node content hash code", sourceNodeContentHashCode2, docLibenditionContentHashCode2); + } + private int countModifier(List nodes, String user) { int count = 0;