From 1cd461a4cb0329a700b8bcfe9eaf6f9569957f6a Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Thu, 17 Nov 2011 14:24:48 +0000 Subject: [PATCH] Merged BRANCHES/DEV/BELARUS/HEAD-ENH-1107 to HEAD: 31986: ENH-1107 : Auditable fix as discussed with Derek, needed when connecting to alfreco sharepoint protocol via Office 2008 for Mac git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@32060 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../repo/audit/AuditableAspectTest.java | 88 +++++++++++++++++++ .../repo/domain/node/AbstractNodeDAOImpl.java | 10 ++- 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/source/java/org/alfresco/repo/audit/AuditableAspectTest.java b/source/java/org/alfresco/repo/audit/AuditableAspectTest.java index 5f1c098be8..ddb00f882c 100644 --- a/source/java/org/alfresco/repo/audit/AuditableAspectTest.java +++ b/source/java/org/alfresco/repo/audit/AuditableAspectTest.java @@ -27,14 +27,18 @@ import java.util.Set; import junit.framework.TestCase; import org.alfresco.model.ContentModel; +import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.policy.BehaviourFilter; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.ContentWriter; 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.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.ApplicationContextHelper; @@ -53,6 +57,7 @@ public class AuditableAspectTest extends TestCase private TransactionService transactionService; private NodeService nodeService; + private ContentService contentService; private BehaviourFilter behaviourFilter; private StoreRef storeRef; @@ -65,6 +70,7 @@ public class AuditableAspectTest extends TestCase // Set the services this.transactionService = serviceRegistry.getTransactionService(); this.nodeService = serviceRegistry.getNodeService(); + this.contentService = serviceRegistry.getContentService(); this.behaviourFilter = (BehaviourFilter) ctx.getBean("policyBehaviourFilter"); AuthenticationUtil.setRunAsUserSystem(); @@ -302,6 +308,88 @@ public class AuditableAspectTest extends TestCase assertAuditableProperties(nodeRef, auditableProps); } + public void testPutContent() throws Exception + { + String fileName = "testContent"; + Map props = new HashMap(); + props.put(ContentModel.PROP_NAME, fileName); + ChildAssociationRef childAssocRef = nodeService.createNode( + rootNodeRef, + ContentModel.ASSOC_CHILDREN, + QName.createQNameWithValidLocalName(NamespaceService.CONTENT_MODEL_1_0_URI, fileName), + ContentModel.TYPE_CONTENT, + props); + final NodeRef nodeRef = childAssocRef.getChildRef(); + + final Date modified = (Date) nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIED); + + RetryingTransactionCallback dateCallback = new RetryingTransactionCallback() + { + + @Override + public Date execute() throws Throwable + { + ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true); + writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); + writer.setEncoding("UTF-8"); + String text = "Test content"; + + writer.putContent(text); + + return (Date) nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIED); + } + }; + + final Date txnModified = transactionService.getRetryingTransactionHelper().doInTransaction(dateCallback); + assertTrue("Last modified date should be changed in individual transaction", modified.getTime() < txnModified.getTime()); + + RetryingTransactionCallback countCallback = new RetryingTransactionCallback() + { + + @Override + public Integer execute() throws Throwable + { + int count = 0; + Date oldModified = txnModified; + + ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true); + writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); + writer.setEncoding("UTF-8"); + String text = "Test content update"; + + writer.putContent(text); + Date newModified = (Date) nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIED); + + if (newModified.getTime() > oldModified.getTime()) + { + count++; + } + + oldModified = newModified; + + writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true); + writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); + writer.setEncoding("UTF-8"); + text = "Test content another update"; + + writer.putContent(text); + + newModified = (Date) nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIED); + + if (newModified.getTime() > oldModified.getTime()) + { + count++; + } + + return count; + } + }; + + Integer count = transactionService.getRetryingTransactionHelper().doInTransaction(countCallback); + + assertTrue("Repeated content uploads in the same transaction should only modify the cm:modified once.", count == 1); + } + private void assertAuditableProperties(NodeRef nodeRef) { assertAuditableProperties(nodeRef, null); diff --git a/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java b/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java index 2e093392fc..3e96f86a7a 100644 --- a/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java @@ -1575,7 +1575,15 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO { auditableProps = new AuditablePropertiesEntity(auditableProps); } - boolean updateAuditableProperties = auditableProps.setAuditValues(null, null, false, 1000L); + long modifiedDateToleranceMs = 1000L; + + if (nodeUpdate.isUpdateTransaction()) + { + // allow update cm:modified property for new transaction + modifiedDateToleranceMs = 0L; + } + + boolean updateAuditableProperties = auditableProps.setAuditValues(null, null, false, modifiedDateToleranceMs); nodeUpdate.setAuditableProperties(auditableProps); nodeUpdate.setUpdateAuditableProperties(updateAuditableProperties); }