mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
[MNT-21953] [MNT-22491] Clear rendition content data on content change. Prevent rendition from having contentHashCode without content (#752)
* [MNT-21953] [MNT-22491] Clear rendition content data on content change. Prevent rendition from having contentHashCode without content * [MNT-21953] [MNT-22491] Added tests * [MNT-21953] [MNT-22491] Removed update content from test * [MNT-21953] [MNT-22491] Improve log messages * [MNT-21953] [MNT-22491] Changed Copyright year to 2021. Minor change in test comments.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -683,6 +683,7 @@ public class RenditionServiceImpl implements
|
||||
log.debug("OnContentUpdate calling RenditionService2.render(\""+sourceNodeRef+"\", \""+renditionName+"\" so we switch to the new service.");
|
||||
}
|
||||
useRenditionService2 = true;
|
||||
renditionService2.clearRenditionContentData(sourceNodeRef, renditionName);
|
||||
renditionService2.render(sourceNodeRef, renditionName);
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -538,9 +538,8 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
}
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Set rendition hashcode " + transformContentHashCode + " and ThumbnailLastModified for " + renditionName);
|
||||
logger.debug("Set ThumbnailLastModified for " + renditionName);
|
||||
}
|
||||
nodeService.setProperty(renditionNode, RenditionModel.PROP_RENDITION_CONTENT_HASH_CODE, transformContentHashCode);
|
||||
setThumbnailLastModified(sourceNodeRef, renditionName);
|
||||
|
||||
if (transformInputStream != null)
|
||||
@@ -554,6 +553,11 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
contentWriter.setEncoding(DEFAULT_ENCODING);
|
||||
ContentWriter renditionWriter = contentWriter;
|
||||
renditionWriter.putContent(transformInputStream);
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Set rendition hashcode for " + renditionName);
|
||||
}
|
||||
nodeService.setProperty(renditionNode, RenditionModel.PROP_RENDITION_CONTENT_HASH_CODE, transformContentHashCode);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -563,16 +567,7 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
}
|
||||
else
|
||||
{
|
||||
Serializable content = nodeService.getProperty(renditionNode, PROP_CONTENT);
|
||||
if (content != null)
|
||||
{
|
||||
nodeService.removeProperty(renditionNode, PROP_CONTENT);
|
||||
nodeService.removeProperty(renditionNode, PROP_RENDITION_CONTENT_HASH_CODE);
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Cleared rendition content and hashcode");
|
||||
}
|
||||
}
|
||||
clearRenditionContentData(renditionNode);
|
||||
}
|
||||
|
||||
if (!sourceHasAspectRenditioned)
|
||||
@@ -736,6 +731,43 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears source nodeRef rendition content and content hash code using supplied rendition name
|
||||
*
|
||||
* @param sourceNodeRef
|
||||
* @param renditionName
|
||||
*/
|
||||
public void clearRenditionContentData(NodeRef sourceNodeRef, String renditionName)
|
||||
{
|
||||
clearRenditionContentData(getRenditionNode(sourceNodeRef, renditionName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears supplied rendition node content (if exists) and content hash code
|
||||
*
|
||||
* @param renditionNode
|
||||
*/
|
||||
private void clearRenditionContentData(NodeRef renditionNode)
|
||||
{
|
||||
if (renditionNode != null)
|
||||
{
|
||||
Serializable content = nodeService.getProperty(renditionNode, PROP_CONTENT);
|
||||
if (content != null)
|
||||
{
|
||||
nodeService.removeProperty(renditionNode, PROP_CONTENT);
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Cleared rendition content");
|
||||
}
|
||||
}
|
||||
nodeService.removeProperty(renditionNode, PROP_RENDITION_CONTENT_HASH_CODE);
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Cleared rendition hashcode");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks whether the specified source node is of a content class which has been registered for
|
||||
* rendition prevention.
|
||||
@@ -886,6 +918,7 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
RenditionDefinition2 renditionDefinition = renditionDefinitionRegistry2.getRenditionDefinition(renditionName);
|
||||
if (renditionDefinition != null)
|
||||
{
|
||||
clearRenditionContentData(sourceNodeRef, renditionName);
|
||||
render(sourceNodeRef, renditionName);
|
||||
}
|
||||
else
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2017 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -640,7 +640,7 @@ public class ThumbnailServiceImpl implements ThumbnailService,
|
||||
boolean valid = true;
|
||||
ContentData content = (ContentData) this.nodeService.getProperty(thumbnailNode, ContentModel.PROP_CONTENT);
|
||||
// (MNT-17162) A thumbnail with an empty content is cached for post-transaction removal, to prevent the delete in read-only transactions.
|
||||
if (content.getSize() == 0)
|
||||
if (content == null || content.getSize() == 0)
|
||||
{
|
||||
TransactionalResourceHelper.getSet(THUMBNAIL_TO_DELETE_NODES).add(thumbnailNode);
|
||||
TransactionSupportUtil.bindListener(this.thumbnailsToDeleteTransactionListener, 0);
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -25,7 +25,16 @@
|
||||
*/
|
||||
package org.alfresco.repo.rendition2;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
import static java.lang.Thread.sleep;
|
||||
import static org.alfresco.model.ContentModel.PROP_CONTENT;
|
||||
import static org.alfresco.model.RenditionModel.PROP_RENDITION_CONTENT_HASH_CODE;
|
||||
import static org.alfresco.repo.content.MimetypeMap.EXTENSION_BINARY;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.content.metadata.AsynchronousExtractor;
|
||||
@@ -60,15 +69,7 @@ import org.quartz.CronExpression;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.lang.Thread.sleep;
|
||||
import static org.alfresco.model.ContentModel.PROP_CONTENT;
|
||||
import static org.alfresco.repo.content.MimetypeMap.EXTENSION_BINARY;
|
||||
import junit.framework.AssertionFailedError;
|
||||
|
||||
/**
|
||||
* Class unites common utility methods for {@link org.alfresco.repo.rendition2} package tests.
|
||||
@@ -531,4 +532,41 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
|
||||
RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
|
||||
txnHelper.doInTransaction(createUserCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to check if the supplied content hash code is valid or not
|
||||
*
|
||||
* @param contentHashCode
|
||||
* the hash code to verify
|
||||
*
|
||||
* @return true in case it is an actual hash code, false otherwise
|
||||
*/
|
||||
protected boolean isValidRenditionContentHashCode(int contentHashCode)
|
||||
{
|
||||
return contentHashCode != RenditionService2Impl.RENDITION2_DOES_NOT_EXIST
|
||||
&& contentHashCode != RenditionService2Impl.SOURCE_HAS_NO_CONTENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method which gets the content hash code from the supplied rendition node without specific validations (the
|
||||
* equivalent method from {@link RenditionService2Impl} is not exposed)
|
||||
*
|
||||
* @param renditionNodeRef
|
||||
* the rendition node
|
||||
*
|
||||
* @return -1 in case of there is no content, -2 in case rendition doesn't exist, the actual content hash code
|
||||
* otherwise
|
||||
*/
|
||||
protected int getRenditionContentHashCode(NodeRef renditionNodeRef)
|
||||
{
|
||||
int renditionContentHashCode = RenditionService2Impl.RENDITION2_DOES_NOT_EXIST;
|
||||
|
||||
if (renditionNodeRef != null)
|
||||
{
|
||||
Serializable hashCode = nodeService.getProperty(renditionNodeRef, PROP_RENDITION_CONTENT_HASH_CODE);
|
||||
renditionContentHashCode = hashCode == null ? RenditionService2Impl.SOURCE_HAS_NO_CONTENT : (int) hashCode;
|
||||
}
|
||||
|
||||
return renditionContentHashCode;
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -25,6 +25,11 @@
|
||||
*/
|
||||
package org.alfresco.repo.rendition2;
|
||||
|
||||
import static org.alfresco.model.ContentModel.PROP_CONTENT;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.RenditionModel;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
@@ -36,16 +41,9 @@ import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.alfresco.model.ContentModel.PROP_CONTENT;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link RenditionService2}
|
||||
*/
|
||||
@@ -308,6 +306,99 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
assertTrue("The rendition should be generated by new Rendition Service", hasRenditionedAspect);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests new {@link RenditionService2Impl#clearRenditionContentData(NodeRef, String)} method.
|
||||
* <p>
|
||||
* This method cleans a rendition content and content hash code.
|
||||
* </p>
|
||||
*/
|
||||
@Test
|
||||
public void testClearRenditionContentData()
|
||||
{
|
||||
// Create a node
|
||||
NodeRef sourceNodeRef = createSource(ADMIN, "quick.jpg");
|
||||
|
||||
// Trigger the rendition
|
||||
render(ADMIN, sourceNodeRef, DOC_LIB);
|
||||
NodeRef renditionNodeRef = waitForRendition(ADMIN, sourceNodeRef, DOC_LIB, true);
|
||||
assertNotNull("Rendition was not generated", renditionNodeRef);
|
||||
assertNotNull("Rendition was not generated", nodeService.getProperty(renditionNodeRef, ContentModel.PROP_CONTENT));
|
||||
|
||||
// Check the rendition content hash code is valid
|
||||
int contentHashCode = getRenditionContentHashCode(renditionNodeRef);
|
||||
assertTrue("Rendition content hash code was not generated", isValidRenditionContentHashCode(contentHashCode));
|
||||
|
||||
// Disable renditionService2
|
||||
renditionService2.setEnabled(false);
|
||||
|
||||
// Call 'clearRenditionContentData' method directly to prove rendition content will be cleaned
|
||||
AuthenticationUtil.runAs((AuthenticationUtil.RunAsWork<Void>) () ->
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(() ->
|
||||
{
|
||||
renditionService2.clearRenditionContentData(sourceNodeRef, DOC_LIB);
|
||||
return null;
|
||||
}), ADMIN);
|
||||
|
||||
// The rendition should not have content by now
|
||||
assertNull("Rendition has content", nodeService.getProperty(renditionNodeRef, ContentModel.PROP_CONTENT));
|
||||
|
||||
// The rendition should not have a content hash code by now
|
||||
contentHashCode = getRenditionContentHashCode(renditionNodeRef);
|
||||
assertFalse("Rendition has content hash code", isValidRenditionContentHashCode(contentHashCode));
|
||||
|
||||
// Enable renditionService2
|
||||
renditionService2.setEnabled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if a rendition without content (but with contentHashCode) can be generated again.
|
||||
* <p>
|
||||
* If the rendition consumption receives a null InputStream, the contentHashCode should be cleaned from the
|
||||
* rendition node, allowing new requests to generate the rendition.
|
||||
* </p>
|
||||
*/
|
||||
@Test
|
||||
public void testRenditionWithoutContentButWithContentHashCode()
|
||||
{
|
||||
// Create a node with an actual rendition
|
||||
NodeRef sourceNodeRef = createSource(ADMIN, "quick.jpg");
|
||||
render(ADMIN, sourceNodeRef, DOC_LIB);
|
||||
NodeRef renditionNodeRef = waitForRendition(ADMIN, sourceNodeRef, DOC_LIB, true);
|
||||
assertNotNull("Rendition was not generated", renditionNodeRef);
|
||||
assertNotNull("Rendition was not generated", nodeService.getProperty(renditionNodeRef, ContentModel.PROP_CONTENT));
|
||||
|
||||
// Clear rendition content (at this point we're forcing a rendition without content but with hash code)
|
||||
clearContent(ADMIN, renditionNodeRef);
|
||||
assertNull("Rendition has content", nodeService.getProperty(renditionNodeRef, ContentModel.PROP_CONTENT));
|
||||
|
||||
// Check that rendition still has the content hash code
|
||||
final int contentHashCode = getRenditionContentHashCode(renditionNodeRef);
|
||||
assertTrue("Rendition content hash code was not generated", isValidRenditionContentHashCode(contentHashCode));
|
||||
|
||||
// Call the 'consume' method directly supplying a null InputStream
|
||||
// This is explicitly called to prove that rendition hash code will be cleaned (as opposite to previous behavior)
|
||||
RenditionDefinition2 renditionDefinition = renditionDefinitionRegistry2.getRenditionDefinition(DOC_LIB);
|
||||
AuthenticationUtil.runAs(() -> {
|
||||
renditionService2.consume(sourceNodeRef, null, renditionDefinition, contentHashCode);
|
||||
return null;
|
||||
}, ADMIN);
|
||||
waitForRendition(ADMIN, sourceNodeRef, DOC_LIB, false);
|
||||
|
||||
// The content hash code should have been cleaned from the rendition node
|
||||
int contentHashCode2 = getRenditionContentHashCode(renditionNodeRef);
|
||||
assertFalse("Rendition content hash code was not cleaned", isValidRenditionContentHashCode(contentHashCode2));
|
||||
|
||||
// Attempts to render the rendition again
|
||||
render(ADMIN, sourceNodeRef, DOC_LIB);
|
||||
NodeRef renditionNodeRef2 = waitForRendition(ADMIN, sourceNodeRef, DOC_LIB, true);
|
||||
assertEquals("New rendition nodeRef is different", renditionNodeRef.toString(), renditionNodeRef2.toString());
|
||||
assertNotNull("New rendition content was not generated", nodeService.getProperty(renditionNodeRef2, ContentModel.PROP_CONTENT));
|
||||
|
||||
// Check the new rendition content hash code
|
||||
int contentHashCode3 = getRenditionContentHashCode(renditionNodeRef2);
|
||||
assertTrue("New rendition content hash code was not generated", isValidRenditionContentHashCode(contentHashCode3));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated can be removed when we remove the original RenditionService
|
||||
*/
|
||||
|
Reference in New Issue
Block a user