diff --git a/repository/src/main/java/org/alfresco/repo/event2/EventGenerator.java b/repository/src/main/java/org/alfresco/repo/event2/EventGenerator.java index 06fea65ba9..eb7a8c5ec7 100644 --- a/repository/src/main/java/org/alfresco/repo/event2/EventGenerator.java +++ b/repository/src/main/java/org/alfresco/repo/event2/EventGenerator.java @@ -27,12 +27,16 @@ package org.alfresco.repo.event2; import java.io.Serializable; import java.net.URI; +import java.time.Instant; +import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.Deque; import java.util.LinkedHashMap; import java.util.Map; import java.util.UUID; +import org.alfresco.repo.domain.node.NodeDAO; +import org.alfresco.repo.domain.node.Transaction; import org.alfresco.repo.event.v1.model.EventType; import org.alfresco.repo.event.v1.model.RepoEvent; import org.alfresco.repo.event2.filter.ChildAssociationTypeFilter; @@ -94,6 +98,7 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin private TransactionService transactionService; private PersonService personService; protected NodeResourceHelper nodeResourceHelper; + private NodeDAO nodeDAO; private NodeTypeFilter nodeTypeFilter; private ChildAssociationTypeFilter childAssociationTypeFilter; @@ -113,6 +118,7 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin PropertyCheck.mandatory(this, "transactionService", transactionService); PropertyCheck.mandatory(this, "personService", personService); PropertyCheck.mandatory(this, "nodeResourceHelper", nodeResourceHelper); + PropertyCheck.mandatory(this, "nodeDAO", nodeDAO); this.nodeTypeFilter = eventFilterRegistry.getNodeTypeFilter(); this.childAssociationTypeFilter = eventFilterRegistry.getChildAssociationTypeFilter(); @@ -145,6 +151,11 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin new JavaBehaviour(this, "beforeDeleteAssociation")); } + public void setNodeDAO(NodeDAO nodeDAO) + { + this.nodeDAO = nodeDAO; + } + public void setPolicyComponent(PolicyComponent policyComponent) { this.policyComponent = policyComponent; @@ -370,13 +381,22 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin private EventInfo getEventInfo(String user) { - return new EventInfo().setTimestamp(ZonedDateTime.now()) + return new EventInfo().setTimestamp(getCurrentTransactionTimestamp()) .setId(UUID.randomUUID().toString()) .setTxnId(AlfrescoTransactionSupport.getTransactionId()) .setPrincipal(user) .setSource(URI.create("/" + descriptorService.getCurrentRepositoryDescriptor().getId())); } + private ZonedDateTime getCurrentTransactionTimestamp() + { + Long currentTransactionId = nodeDAO.getCurrentTransactionId(false); + Transaction transaction = nodeDAO.getTxnById(currentTransactionId); + Instant commitTimeMs = Instant.ofEpochMilli(transaction.getCommitTimeMs()); + ZonedDateTime timestamp = ZonedDateTime.ofInstant(commitTimeMs, ZoneOffset.UTC); + return timestamp; + } + @Override protected void onBootstrap(ApplicationEvent applicationEvent) { diff --git a/repository/src/main/resources/alfresco/events2-context.xml b/repository/src/main/resources/alfresco/events2-context.xml index c5d899023f..979b4f6cd8 100644 --- a/repository/src/main/resources/alfresco/events2-context.xml +++ b/repository/src/main/resources/alfresco/events2-context.xml @@ -41,6 +41,7 @@ + diff --git a/repository/src/test/java/org/alfresco/repo/event2/CreateRepoEventIT.java b/repository/src/test/java/org/alfresco/repo/event2/CreateRepoEventIT.java index 7496f7633a..db6b592c70 100644 --- a/repository/src/test/java/org/alfresco/repo/event2/CreateRepoEventIT.java +++ b/repository/src/test/java/org/alfresco/repo/event2/CreateRepoEventIT.java @@ -26,9 +26,14 @@ package org.alfresco.repo.event2; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.util.List; import org.alfresco.model.ContentModel; +import org.alfresco.repo.domain.node.NodeDAO; +import org.alfresco.repo.domain.node.Transaction; import org.alfresco.repo.event.v1.model.EventData; import org.alfresco.repo.event.v1.model.EventType; import org.alfresco.repo.event.v1.model.NodeResource; @@ -38,6 +43,7 @@ import org.alfresco.service.namespace.QName; import org.alfresco.util.GUID; import org.alfresco.util.PropertyMap; import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; /** * @author Iulian Aftene @@ -45,6 +51,9 @@ import org.junit.Test; public class CreateRepoEventIT extends AbstractContextAwareRepoEvent { + @Autowired + private NodeDAO nodeDAO; + @Test public void testCreateEvent() { @@ -149,9 +158,32 @@ public class CreateRepoEventIT extends AbstractContextAwareRepoEvent assertTrue("isFile flag should be TRUE for nodeType=cm:content. ", resource.isFile()); assertFalse("isFolder flag should be FALSE for nodeType=cm:content. ", resource.isFolder()); } + + @Test + public void testEventTimestampEqualsToTransactionCommitTime() + { + String name = "TestFile-" + System.currentTimeMillis() + ".txt"; + PropertyMap propertyMap = new PropertyMap(); + propertyMap.put(ContentModel.PROP_NAME, name); + + //create a node and return the transaction id required later + Long transactionId = retryingTransactionHelper.doInTransaction(() -> { + nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, + QName.createQName(TEST_NAMESPACE, GUID.generate()), ContentModel.TYPE_CONTENT, propertyMap).getChildRef(); + return nodeDAO.getCurrentTransactionId(false); + }); + + RepoEvent> resultRepoEvent = getRepoEvent(1); + + Transaction transaction = nodeDAO.getTxnById(transactionId); + Instant commitTimeMs = Instant.ofEpochMilli(transaction.getCommitTimeMs()); + ZonedDateTime timestamp = ZonedDateTime.ofInstant(commitTimeMs, ZoneOffset.UTC); + + assertEquals(timestamp, resultRepoEvent.getTime()); + } @Test - public void testCteateMultipleNodesInTheSameTransaction() + public void testCreateMultipleNodesInTheSameTransaction() { retryingTransactionHelper.doInTransaction(() -> { for (int i = 0; i < 3; i++)