Merged HEAD-BUG-FIX to HEAD (4.2)

55488: MNT-9648: Merged V4.1-BUG-FIX (4.1.7) to HEAD-BUG-FIX (4.2)
      55001: Merged DEV to BRANCHES/DEV/V4.1-BUG-FIX:
         54951: Test to reproduce MNT-9580: Daisy chained cm:original associations are cascade-deleted when the first original is deleted
         54952: Fix MNT-9580: Daisy chained cm:original associations are cascade-deleted when the first original is deleted
               When an aspect is removed, the associations defined on the aspect were also being removed.
               However, the *inbound* associations instances were also being removed; in effect the behaviour of aspects on
               other nodes was being activated, which is incorrect.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@55793 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Alan Davis
2013-09-21 16:07:46 +00:00
parent 9e406a53ba
commit 0d3580b1c8
2 changed files with 67 additions and 16 deletions

View File

@@ -966,22 +966,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
nodeAssocIdsToRemove.add(assocPair.getFirst()); nodeAssocIdsToRemove.add(assocPair.getFirst());
assocRefsRemoved.add(assocPair.getSecond()); assocRefsRemoved.add(assocPair.getSecond());
} }
Collection<Pair<Long, AssociationRef>> sourceAssocRefs = nodeDAO.getSourceNodeAssocs(nodeId, assocTypeQName); // MNT-9580: Daisy chained cm:original associations are cascade-deleted when the first original is deleted
for (Pair<Long, AssociationRef> assocPair : sourceAssocRefs) // As a side-effect of the investigation of MNT-9446, it was dicovered that inbound associations (ones pointing *to* this aspect)
{ // were also being removed. This is incorrect because the aspect being removed here has no say over who points at it.
if (isPendingDelete(assocPair.getSecond().getSourceRef())) // Therefore, do not remove inbound associations because we only define outbound associations on types and aspects.
{ // Integrity checking will ensure that the correct behaviours are in place to maintain model integrity.
if (logger.isTraceEnabled())
{
logger.trace(
"Aspect-triggered association removal: " +
"Ignoring peer associations where one of the nodes is pending delete: " + assocPair);
}
continue;
}
nodeAssocIdsToRemove.add(assocPair.getFirst());
assocRefsRemoved.add(assocPair.getSecond());
}
} }
// Now delete peer associations // Now delete peer associations
int assocsDeleted = nodeDAO.removeNodeAssocs(nodeAssocIdsToRemove); int assocsDeleted = nodeDAO.removeNodeAssocs(nodeAssocIdsToRemove);

View File

@@ -634,6 +634,68 @@ public class CopyServiceImplTest extends TestCase
assertFalse("Copy should not have cm:copiedfrom aspect. ", nodeService.hasAspect(firstCopy, ContentModel.ASPECT_COPIEDFROM)); assertFalse("Copy should not have cm:copiedfrom aspect. ", nodeService.hasAspect(firstCopy, ContentModel.ASPECT_COPIEDFROM));
} }
/**
* <a href="https://issues.alfresco.com/jira/browse/MNT-9580">
* MNT-9580: Daisy chained cm:original associations are cascade-deleted when the first original is deleted
* </a>
*/
public void testCopyOfCopyOfCopy()
{
IntegrityChecker integrityChecker = (IntegrityChecker) ctx.getBean("integrityChecker");
// Create the node used for copying
ChildAssociationRef childAssocRef = nodeService.createNode(
rootNodeRef,
ContentModel.ASSOC_CHILDREN,
QName.createQName("{test}test"),
TEST_TYPE_QNAME,
createTypePropertyBag());
NodeRef nodeRef = childAssocRef.getChildRef();
PagingRequest pageRequest = new PagingRequest(10);
pageRequest.setRequestTotalCountMax(200);
PagingResults<CopyInfo> copies = null;
NodeRef currentOriginal = nodeRef;
NodeRef copyNodeRef = null;
for (int i = 1; i <= 5; i++)
{
copyNodeRef = copyService.copy(
currentOriginal,
rootNodeRef,
ContentModel.ASSOC_CHILDREN,
QName.createQName("{test}copyAssoc"+i));
copies = copyService.getCopies(currentOriginal, pageRequest);
assertEquals("Incorrect number of copies on iteration " + i, 1, copies.getPage().size());
// Check that the original node can be retrieved
NodeRef originalCheck = copyService.getOriginal(copyNodeRef);
assertEquals("Original is not as expected. ", currentOriginal, originalCheck);
// Run integrity checks to ensure that commit has a chance
integrityChecker.checkIntegrity();
currentOriginal = copyNodeRef;
}
// Now, delete the nodes starting with the first original
currentOriginal = nodeRef;
copyNodeRef = null;
for (int i = 1; i < 5; i++)
{
// Each node must be an original
copies = copyService.getCopies(currentOriginal, pageRequest);
assertEquals("Incorrect number of copies on iteration " + i, 1, copies.getPage().size());
copyNodeRef = copies.getPage().get(0).getNodeRef();
// Delete current original
nodeService.deleteNode(currentOriginal);
// Run integrity checks to ensure that commit has a chance
integrityChecker.checkIntegrity();
currentOriginal = copyNodeRef;
}
}
/** /**
* Test the behaviour of the aspect when copying types not derived from <b>cm:object</b> * Test the behaviour of the aspect when copying types not derived from <b>cm:object</b>
*/ */