diff --git a/repository/src/main/java/org/alfresco/repo/event2/filter/NodePropertyFilter.java b/repository/src/main/java/org/alfresco/repo/event2/filter/NodePropertyFilter.java index fd211472163..d6a4d70bdfb 100644 --- a/repository/src/main/java/org/alfresco/repo/event2/filter/NodePropertyFilter.java +++ b/repository/src/main/java/org/alfresco/repo/event2/filter/NodePropertyFilter.java @@ -2,7 +2,7 @@ * #%L * Alfresco Repository * %% - * Copyright (C) 2005 - 2020 Alfresco Software Limited + * Copyright (C) 2005 - 2023 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -48,19 +48,31 @@ public class NodePropertyFilter extends AbstractNodeEventFilter ContentModel.PROP_CREATOR, ContentModel.PROP_CREATED, ContentModel.PROP_CONTENT); + // These properties should not be excluded from the properties object + private static final Set ALLOWED_PROPERTIES = Set.of(ContentModel.PROP_CASCADE_TX, + ContentModel.PROP_CASCADE_CRC); - private final List nodeAspectsBlackList; + private final List nodePropertiesBlackList; public NodePropertyFilter() { - this.nodeAspectsBlackList = parseFilterList(FILTERED_PROPERTIES); + this.nodePropertiesBlackList = parseFilterList(FILTERED_PROPERTIES); } @Override public Set getExcludedTypes() { Set result = new HashSet<>(EXCLUDED_TOP_LEVEL_PROPS); - nodeAspectsBlackList.forEach(nodeAspect -> result.addAll(expandTypeDef(nodeAspect))); + nodePropertiesBlackList.forEach(nodeProperty-> result.addAll(expandTypeDef(nodeProperty))); return result; } + + @Override + public boolean isExcluded(QName qName) + { + if(qName != null && ALLOWED_PROPERTIES.contains(qName)){ + return false; + } + return super.isExcluded(qName); + } } diff --git a/repository/src/main/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java b/repository/src/main/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java index e0c19856b9b..73731c46045 100644 --- a/repository/src/main/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java +++ b/repository/src/main/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java @@ -2,7 +2,7 @@ * #%L * Alfresco Repository * %% - * Copyright (C) 2005 - 2022 Alfresco Software Limited + * Copyright (C) 2005 - 2023 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -3203,13 +3203,16 @@ else if (!nodeDAO.hasNodeAspect(childNodeId, ContentModel.ASPECT_AUDITABLE)) // Invoke policy behaviour invokeBeforeUpdateNode(parentNodeRef); + Map propertiesBefore = nodeDAO.getNodeProperties(parentNodeId); // Touch the node; it is cm:auditable boolean changed = nodeDAO.setModifiedProperties(parentNodeId, modifiedDate, modifiedByToPropagate); if (changed) { + Map propertiesAfter = nodeDAO.getNodeProperties(parentNodeId); // Invoke policy behaviour invokeOnUpdateNode(parentNodeRef); + invokeOnUpdateProperties(parentNodeRef, propertiesBefore, propertiesAfter); } return null; diff --git a/repository/src/test/java/org/alfresco/repo/audit/access/AccessAuditorTest.java b/repository/src/test/java/org/alfresco/repo/audit/access/AccessAuditorTest.java index 32907378208..d1ddfc656e4 100644 --- a/repository/src/test/java/org/alfresco/repo/audit/access/AccessAuditorTest.java +++ b/repository/src/test/java/org/alfresco/repo/audit/access/AccessAuditorTest.java @@ -158,7 +158,7 @@ public Map answer(InvocationOnMock invocation) throws Thro { Object[] args = invocation.getArguments(); Map auditMap = (Map)args[1]; - if ("/alfresco-access/transaction".equals(args[0])) + if ("/alfresco-access/transaction".equals(args[0]) && !"updateNodeProperties".equals(auditMap.get("action"))) { auditMapList.add(auditMap); } diff --git a/repository/src/test/java/org/alfresco/repo/event2/ChildAssociationRepoEventIT.java b/repository/src/test/java/org/alfresco/repo/event2/ChildAssociationRepoEventIT.java index 11b6bcf77dc..486d0041f95 100644 --- a/repository/src/test/java/org/alfresco/repo/event2/ChildAssociationRepoEventIT.java +++ b/repository/src/test/java/org/alfresco/repo/event2/ChildAssociationRepoEventIT.java @@ -2,7 +2,7 @@ * #%L * Alfresco Repository * %% - * Copyright (C) 2005 - 2020 Alfresco Software Limited + * Copyright (C) 2005 - 2023 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -77,9 +77,9 @@ public void testAddChildAssociation() assertEquals(1, childAssociationRefs.size()); assertFalse(childAssociationRefs.get(0).isPrimary()); - checkNumOfEvents(3); + checkNumOfEvents(4); - final RepoEvent> childAssocRepoEvent = getRepoEventWithoutWait(3); + final RepoEvent> childAssocRepoEvent = getFilteredEvent(EventType.CHILD_ASSOC_CREATED, 0); assertEquals("Wrong repo event type.", EventType.CHILD_ASSOC_CREATED.getType(), childAssocRepoEvent.getType()); assertNotNull("Repo event ID is not available.", childAssocRepoEvent.getId()); @@ -131,7 +131,7 @@ public void testRemoveChildAssociation() assertEquals(1, childAssociationRefs.size()); assertFalse(childAssociationRefs.get(0).isPrimary()); - checkNumOfEvents(3); + checkNumOfEvents(4); retryingTransactionHelper.doInTransaction(() -> nodeService.removeChildAssociation(childAssociationRef)); @@ -141,9 +141,9 @@ public void testRemoveChildAssociation() assertEquals(0, childAssociationRefs.size()); - checkNumOfEvents(4); + checkNumOfEvents(6); - final RepoEvent> childAssocRepoEvent = getRepoEventWithoutWait(4); + final RepoEvent> childAssocRepoEvent = getFilteredEvent(EventType.CHILD_ASSOC_DELETED, 0); assertEquals("Wrong repo event type.", EventType.CHILD_ASSOC_DELETED.getType(), childAssocRepoEvent.getType()); assertNotNull("Repo event ID is not available. ", childAssocRepoEvent.getId()); @@ -212,7 +212,7 @@ public void testOneChildListOfParentsAssociations() return null; }); - checkNumOfEvents(7); + checkNumOfEvents(8); // 3 assoc.child.Created events should be created @@ -268,7 +268,7 @@ public void testOneChildMultipleParentsSameTransaction() return null; }); - checkNumOfEvents(7); + checkNumOfEvents(8); // 3 assoc.child.Created events should be created List>> childAssocEvents = getFilteredEvents(EventType.CHILD_ASSOC_CREATED); assertEquals("Wrong association events number",3, childAssocEvents.size()); @@ -330,7 +330,7 @@ public void testOneChildMultipleParentsDifferentTransaction() return null; }); - checkNumOfEvents(7); + checkNumOfEvents(10); // 3 assoc.child.Created events should be created List>> childAssocEvents = getFilteredEvents(EventType.CHILD_ASSOC_CREATED); assertEquals("Wrong association events number",3, childAssocEvents.size()); @@ -388,7 +388,7 @@ public void testOneParentMultipleChildrenSameTransaction() return null; }); - checkNumOfEvents(7); + checkNumOfEvents(10); // 3 assoc.child.Created events should be created List>> childAssocEvents = getFilteredEvents(EventType.CHILD_ASSOC_CREATED); assertEquals("Wrong association events number",3, childAssocEvents.size()); @@ -432,7 +432,7 @@ public void testOneParentMultipleChildrenDifferentTransaction() return null; }); - checkNumOfEvents(7); + checkNumOfEvents(10); // 3 assoc.child.Created events should be created List>> childAssocEvents = getFilteredEvents(EventType.CHILD_ASSOC_CREATED); assertEquals("Wrong association events number",3, childAssocEvents.size()); @@ -501,7 +501,7 @@ public void testDeleteAssociationsOneChildMultipleParentsSameTransaction() return null; }); - checkNumOfEvents(10); + checkNumOfEvents(12); // 3 assoc.child.Deleted events should be created List>> childAssocEvents = getFilteredEvents(EventType.CHILD_ASSOC_DELETED); @@ -557,7 +557,7 @@ public void testDeleteAssociationOneParentMultipleChildrenDifferentTransactions( nodeService.removeChildAssociation(childAssociationRef)); } - checkNumOfEvents(10); + checkNumOfEvents(14); // 3 assoc.child.Deleted events should be created List>> childAssocEvents = getFilteredEvents(EventType.CHILD_ASSOC_DELETED); @@ -619,7 +619,7 @@ public void testDeleteParentWithMultipleChildAssociations() deleteNode(parentNodeRef); - checkNumOfEvents(11); + checkNumOfEvents(17); // 3 assoc.child.Deleted events should be created List>> childAssocEvents = getFilteredEvents(EventType.CHILD_ASSOC_DELETED); @@ -670,7 +670,7 @@ public void testDeleteChildWithMultipleParentAssociations() deleteNode(childNodeRef); - checkNumOfEvents(11); + checkNumOfEvents(12); // 3 assoc.child.Deleted events should be created List>> childAssocEvents = getFilteredEvents(EventType.CHILD_ASSOC_DELETED); @@ -708,13 +708,14 @@ public void testUpdateNodeAddChildAssociationNodeEventsFirst() assertEquals(1, childAssociationRefs.size()); assertFalse(childAssociationRefs.get(0).isPrimary()); - checkNumOfEvents(4); + checkNumOfEvents(5); // Check the node events occur before the child association event List> repoEvents = getRepoEventsContainer().getEvents(); assertEquals("org.alfresco.event.node.Created", repoEvents.get(0).getType()); assertEquals("org.alfresco.event.node.Created", repoEvents.get(1).getType()); assertEquals("org.alfresco.event.node.Updated", repoEvents.get(2).getType()); - assertEquals("org.alfresco.event.assoc.child.Created", repoEvents.get(3).getType()); + assertEquals("org.alfresco.event.node.Updated", repoEvents.get(3).getType()); + assertEquals("org.alfresco.event.assoc.child.Created", repoEvents.get(4).getType()); } } diff --git a/repository/src/test/java/org/alfresco/repo/event2/EventFilterUnitTest.java b/repository/src/test/java/org/alfresco/repo/event2/EventFilterUnitTest.java index db6779b163d..25c60567813 100644 --- a/repository/src/test/java/org/alfresco/repo/event2/EventFilterUnitTest.java +++ b/repository/src/test/java/org/alfresco/repo/event2/EventFilterUnitTest.java @@ -119,6 +119,9 @@ public void nodePropertyFilter() assertTrue("System properties are excluded by default.", propertyFilter.isExcluded(ContentModel.PROP_NODE_DBID)); + assertFalse("Property cascadeTx is not excluded", propertyFilter.isExcluded(ContentModel.PROP_CASCADE_TX)); + assertFalse("Property cascadeCRC is not excluded", propertyFilter.isExcluded(ContentModel.PROP_CASCADE_CRC)); + assertFalse(propertyFilter.isExcluded(ContentModel.PROP_TITLE)); } diff --git a/repository/src/test/java/org/alfresco/repo/event2/UpdateRepoEventIT.java b/repository/src/test/java/org/alfresco/repo/event2/UpdateRepoEventIT.java index a7a5ad071ab..c6efe5ef5e9 100644 --- a/repository/src/test/java/org/alfresco/repo/event2/UpdateRepoEventIT.java +++ b/repository/src/test/java/org/alfresco/repo/event2/UpdateRepoEventIT.java @@ -87,7 +87,7 @@ public void testUpdateNodeResourceContent() }); checkNumOfEvents(2); - + resultRepoEvent = getRepoEvent(2); assertEquals("Wrong repo event type.", EventType.NODE_UPDATED.getType(), resultRepoEvent.getType()); @@ -227,7 +227,7 @@ public void testUpdateNodeResourceContentSameContentSize() }); checkNumOfEvents(2); - + resultRepoEvent = getRepoEvent(2); assertEquals("Wrong repo event type.", EventType.NODE_UPDATED.getType(), resultRepoEvent.getType()); @@ -625,7 +625,7 @@ public void testUpdateNodeTypeWithCustomType() // Create active model CustomModelDefinition modelDefinition = - retryingTransactionHelper.doInTransaction(() -> customModelService.createCustomModel(model, true)); + retryingTransactionHelper.doInTransaction(() -> customModelService.createCustomModel(model, true)); assertNotNull(modelDefinition); assertEquals(modelName, modelDefinition.getName().getLocalName()); @@ -635,8 +635,11 @@ public void testUpdateNodeTypeWithCustomType() Collection types = modelDefinition.getTypeDefinitions(); assertEquals(1, types.size()); + // we should have only 2 events, node.Created and node.Updated + checkNumOfEvents(2); + // node.Created event should be generated for the model - RepoEvent> resultRepoEvent = getRepoEvent(1); + RepoEvent> resultRepoEvent = getFilteredEvent(EventType.NODE_CREATED, 0); assertEquals("Wrong repo event type.", EventType.NODE_CREATED.getType(), resultRepoEvent.getType()); NodeResource nodeResource = getNodeResource(resultRepoEvent); assertEquals("Incorrect node type was found", "cm:dictionaryModel", nodeResource.getNodeType()); @@ -647,9 +650,9 @@ public void testUpdateNodeTypeWithCustomType() assertEquals(ContentModel.TYPE_CONTENT, nodeService.getType(nodeRef)); // node.Created event should be generated - resultRepoEvent = getRepoEvent(2); - assertEquals("Wrong repo event type.", EventType.NODE_CREATED.getType(), resultRepoEvent.getType()); + resultRepoEvent = getRepoEvent(3); nodeResource = getNodeResource(resultRepoEvent); + assertEquals("Wrong repo event type.", EventType.NODE_CREATED.getType(), resultRepoEvent.getType()); assertEquals("cm:content node type was not found", "cm:content", nodeResource.getNodeType()); QName typeQName = QName.createQName("{" + namespacePair.getFirst()+ "}" + typeName); @@ -661,15 +664,15 @@ public void testUpdateNodeTypeWithCustomType() return null; }); - // we should have 3 events, node.Created for the model, node.Created for the node and node.Updated - checkNumOfEvents(3); + // we should have 4 events, node.Created for the model, node.Updated for the parent, node.Created for the node and node.Updated + checkNumOfEvents(4); - resultRepoEvent = getRepoEvent(3); + resultRepoEvent = getRepoEvent(4); assertEquals("Wrong repo event type.", EventType.NODE_UPDATED.getType(), resultRepoEvent.getType()); nodeResource = getNodeResource(resultRepoEvent); assertEquals("Incorrect node type was found", namespacePair.getSecond() + QName.NAMESPACE_PREFIX + typeName, nodeResource.getNodeType()); - NodeResource resourceBefore = getNodeResourceBefore(3); + NodeResource resourceBefore = getNodeResourceBefore(4); assertEquals("Incorrect node type was found", "cm:content", resourceBefore.getNodeType()); assertNull(resourceBefore.getId()); assertNull(resourceBefore.getContent()); @@ -788,7 +791,7 @@ public void testMoveFile() }); checkNumOfEvents(4); - + NodeResource resourceBefore = getNodeResourceBefore(4); NodeResource resource = getNodeResource(4); @@ -808,7 +811,7 @@ public void testMoveFile() assertNull(resourceBefore.getModifiedByUser()); assertNull(resourceBefore.getCreatedAt()); assertNull(resourceBefore.getCreatedByUser()); - assertNull(resourceBefore.getProperties()); + assertNotNull(resourceBefore.getProperties()); assertNull(resourceBefore.getAspectNames()); assertNotNull(resourceBefore.getPrimaryHierarchy()); assertNull("Content should have been null.", resource.getContent()); @@ -818,7 +821,7 @@ public void testMoveFile() assertNotNull(resource.getModifiedByUser()); assertNotNull(resource.getAspectNames()); assertNull(resource.getContent()); - assertTrue(resource.getProperties().isEmpty()); + assertFalse(resource.getProperties().isEmpty()); } @Test @@ -1020,7 +1023,7 @@ public void testAddAspectRemoveAspectAddAspectFromContentSameTransactionTest() NodeResource resource = getNodeResource(1); final Set originalAspects = resource.getAspectNames(); assertNotNull(originalAspects); - + retryingTransactionHelper.doInTransaction(() -> { // Add cm:geographic aspect with default value nodeService.addAspect(nodeRef, ContentModel.ASPECT_GEOGRAPHIC, null);