diff --git a/config/alfresco/model/transferModel.xml b/config/alfresco/model/transferModel.xml index 36f9c086e4..708aec5a12 100644 --- a/config/alfresco/model/transferModel.xml +++ b/config/alfresco/model/transferModel.xml @@ -208,14 +208,8 @@ Alien Node - Nodes with this aspect are either alien nodes or have been invaded by alien content + Nodes with this aspect are either alien nodes or have been invaded by other alien nodes - - Alien Content - d:boolean - false - false - The repositories that have invaded this node d:text diff --git a/source/java/org/alfresco/repo/transfer/AlienProcessorImpl.java b/source/java/org/alfresco/repo/transfer/AlienProcessorImpl.java index cd1c7d3534..758d1a1cd0 100644 --- a/source/java/org/alfresco/repo/transfer/AlienProcessorImpl.java +++ b/source/java/org/alfresco/repo/transfer/AlienProcessorImpl.java @@ -148,7 +148,7 @@ public class AlienProcessorImpl implements AlienProcessor public void beforeDeleteAlien(NodeRef deletedNodeRef) { - log.debug("on delete node - need to check for transferred node"); + log.debug("before delete node - need to check for alien invaders"); Liststuff = (List)nodeService.getProperty(deletedNodeRef, TransferModel.PROP_INVADED_BY); @@ -272,12 +272,18 @@ public class AlienProcessorImpl implements AlienProcessor return nodeService.hasAspect(nodeRef, TransferModel.ASPECT_ALIEN); } - public void pruneNode(NodeRef parentNodeRef, String fromRepositoryId) + public void pruneNode(NodeRef nodeToPrune, String fromRepositoryId) { Stack nodesToPrune = new Stack(); - Stack foldersToRecalculate = new Stack(); - nodesToPrune.add(parentNodeRef); - + nodesToPrune.add(nodeToPrune); + + ChildAssociationRef startingParent = nodeService.getPrimaryParent(nodeToPrune); + + Stack foldersToRecalculate = new Stack(); + + /** + * Now go and do the pruning. + */ while(!nodesToPrune.isEmpty()) { /** @@ -297,6 +303,7 @@ public class AlienProcessorImpl implements AlienProcessor ListinvadedBy = (List)getNodeService().getProperty(currentNodeRef, TransferModel.PROP_INVADED_BY); if(invadedBy.contains(fromRepositoryId)) { + // Yes we are invaded by fromRepositoryId if(invadedBy.size() == 1) { // we are invaded by a single repository which must be fromRepositoryId @@ -307,23 +314,24 @@ public class AlienProcessorImpl implements AlienProcessor { log.debug("folder has multiple invaders"); // multiple invasion - so it must be a folder + //TODO replace with a more efficient query - List refs = getNodeService().getChildAssocs(parentNodeRef); + List refs = getNodeService().getChildAssocs(currentNodeRef); for(ChildAssociationRef ref : refs) { if(log.isDebugEnabled()) { log.debug("will need to check child:" + ref); } - nodesToPrune.push(ref.getChildRef()); - - /** - * This folder can't be deleted so its invaded flag needs to be re-calculated - */ - if(!foldersToRecalculate.contains(ref.getParentRef())) - { - foldersToRecalculate.push(ref.getParentRef()); - } + nodesToPrune.push(ref.getChildRef()); + } + + /** + * Yes we might do something to the children of this node. + */ + if(!foldersToRecalculate.contains(currentNodeRef)) + { + foldersToRecalculate.push(currentNodeRef); } } } @@ -353,9 +361,9 @@ public class AlienProcessorImpl implements AlienProcessor /** * This folder can't be deleted so its invaded flag needs to be re-calculated */ - if(!foldersToRecalculate.contains(ref.getParentRef())) + if(!foldersToRecalculate.contains(currentNodeRef)) { - foldersToRecalculate.push(ref.getParentRef()); + foldersToRecalculate.push(currentNodeRef); } } } @@ -379,44 +387,52 @@ public class AlienProcessorImpl implements AlienProcessor } /** - * Now ripple the "invadedBy" flag upwards. + * Now recalculate the "invadedBy" flag for those folders we could not delete. */ - while(!foldersToRecalculate.isEmpty()) { NodeRef folderNodeRef = foldersToRecalculate.pop(); log.debug("recalculate invadedBy :" + folderNodeRef); - ListfolderInvadedBy = (List)getNodeService().getProperty(folderNodeRef, TransferModel.PROP_INVADED_BY); - - boolean stillInvaded = false; - //TODO need a more efficient query here - List refs = getNodeService().getChildAssocs(folderNodeRef); - for(ChildAssociationRef ref : refs) + recalcInvasion(folderNodeRef, fromRepositoryId); + } + + /** + * Now ripple up the invaded flag - may be a alien retreat. + */ + log.debug("now ripple upwards"); + + ChildAssociationRef ripple = startingParent; + while(ripple != null) + { + if(log.isDebugEnabled()) { - NodeRef childNode = ref.getChildRef(); - ListchildInvadedBy = (List)getNodeService().getProperty(childNode, TransferModel.PROP_INVADED_BY); - - if(childInvadedBy.contains(fromRepositoryId)) + log.debug("Checking parent:" + ripple); + } + + if(nodeService.hasAspect(ripple.getParentRef(), TransferModel.ASPECT_ALIEN)) + { + if(recalcInvasion(ripple.getParentRef(), fromRepositoryId)) { - log.debug("folder is still invaded"); - stillInvaded = true; - break; + log.debug("parent is still invaded"); + ripple = null; + } + else + { + log.debug("parent is no longer invaded"); + ripple = nodeService.getPrimaryParent(ripple.getParentRef()); } } - - if(!stillInvaded) + else { - List newInvadedBy = new ArrayList(folderInvadedBy); - folderInvadedBy.remove(fromRepositoryId); - getNodeService().setProperty(folderNodeRef, TransferModel.PROP_INVADED_BY, (Serializable)newInvadedBy); - } + ripple = null; + } } + log.debug("pruneNode: end"); } - /** * Is this node invaded ? * @param nodeRef @@ -436,9 +452,9 @@ public class AlienProcessorImpl implements AlienProcessor } /** - * Mark the specified node as an alien node, invadedby the invader. - * @param newAlien - * @param invader + * Mark the specified node as an alien node, invaded by the specified invader. + * @param newAlien node that has been invaded. + * @param invader the repository id of the invading repo. */ private void setAlien(NodeRef newAlien, String invader) { @@ -448,23 +464,70 @@ public class AlienProcessorImpl implements AlienProcessor if(invadedBy == null) { - nodeService.setProperty(newAlien, TransferModel.PROP_ALIEN, Boolean.TRUE); invadedBy = new ArrayList(1); } - invadedBy.add(invader); + + if(!invadedBy.contains(invader)) + { + invadedBy.add(invader); + } /** * Set the invaded by property */ - nodeService.setProperty(newAlien, TransferModel.PROP_INVADED_BY, (Serializable) invadedBy); - -// /** -// * Experiment with a residual property -// */ -// nodeService.setProperty(newAlien, QName.createQName(TransferModel.TRANSFER_MODEL_1_0_URI, -// "invader" + invader), Boolean.TRUE); - + nodeService.setProperty(newAlien, TransferModel.PROP_INVADED_BY, (Serializable) invadedBy); } + + /** + * Recalculate the whether this node is invaded by the specified repository + * @param folderNodeRef the node to re-calculate + * @param fromRepositoryId the repository who is transferring. + * + * @return true - still invaded, false, no longer invaded + */ + private boolean recalcInvasion(NodeRef folderNodeRef, String fromRepositoryId) + { + ListfolderInvadedBy = (List)nodeService.getProperty(folderNodeRef, TransferModel.PROP_INVADED_BY); + + boolean stillInvaded = false; + + //TODO need a more efficient query here + List refs = nodeService.getChildAssocs(folderNodeRef); + for(ChildAssociationRef ref : refs) + { + NodeRef childNode = ref.getChildRef(); + ListchildInvadedBy = (List)getNodeService().getProperty(childNode, TransferModel.PROP_INVADED_BY); + + if(childInvadedBy != null && childInvadedBy.contains(fromRepositoryId)) + { + log.debug("folder is still invaded"); + stillInvaded = true; + break; + } + } + + if(!stillInvaded) + { + log.debug("folder is no longer invaded by this repo:" + folderNodeRef); + folderInvadedBy.remove(fromRepositoryId); + if(folderInvadedBy.size() > 0) + { + if(log.isDebugEnabled()) + { + log.debug("still invaded by:" + folderInvadedBy); + } + getNodeService().setProperty(folderNodeRef, TransferModel.PROP_INVADED_BY, (Serializable)folderInvadedBy); + } + else + { + log.debug("no longer alien:" + folderNodeRef); + getNodeService().removeAspect(folderNodeRef, TransferModel.ASPECT_ALIEN); + } + } + + return stillInvaded; + } + public void setNodeService(NodeService nodeService) { this.nodeService = nodeService; diff --git a/source/java/org/alfresco/repo/transfer/DefaultManifestProcessorFactoryImpl.java b/source/java/org/alfresco/repo/transfer/DefaultManifestProcessorFactoryImpl.java index 17734500c7..71b2ce41cb 100644 --- a/source/java/org/alfresco/repo/transfer/DefaultManifestProcessorFactoryImpl.java +++ b/source/java/org/alfresco/repo/transfer/DefaultManifestProcessorFactoryImpl.java @@ -69,6 +69,7 @@ public class DefaultManifestProcessorFactoryImpl implements ManifestProcessorFac RepoTertiaryManifestProcessorImpl tertiaryProcessor = new RepoTertiaryManifestProcessorImpl(receiver, transferId); tertiaryProcessor.setNodeService(nodeService); tertiaryProcessor.setAlienProcessor(getAlienProcessor()); + tertiaryProcessor.setNodeResolver(nodeResolver); processors.add(tertiaryProcessor); return processors; diff --git a/source/java/org/alfresco/repo/transfer/RepoPrimaryManifestProcessorImpl.java b/source/java/org/alfresco/repo/transfer/RepoPrimaryManifestProcessorImpl.java index fb2f6ae148..a6c97f7391 100644 --- a/source/java/org/alfresco/repo/transfer/RepoPrimaryManifestProcessorImpl.java +++ b/source/java/org/alfresco/repo/transfer/RepoPrimaryManifestProcessorImpl.java @@ -136,63 +136,35 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB // If we can find a corresponding node then we'll delete it. // If we can't find a corresponding node then we'll do nothing. logProgress("Processing incoming deleted node: " + node.getNodeRef()); - if (!nodeService.exists(node.getNodeRef())) + + ChildAssociationRef origPrimaryParent = node.getPrimaryParentAssoc(); + NodeRef origNodeRef = new NodeRef(origPrimaryParent.getParentRef().getStoreRef(), node.getNodeRef().getId()); + + CorrespondingNodeResolver.ResolvedParentChildPair resolvedNodes = nodeResolver.resolveCorrespondingNode( + origNodeRef, origPrimaryParent, node.getParentPath()); + + // Does a corresponding node exist in this repo? + if (resolvedNodes.resolvedChild != null) { - // It's not in our archive store. Check to see if we can find it in - // its original store... - ChildAssociationRef origPrimaryParent = node.getPrimaryParentAssoc(); - NodeRef origNodeRef = new NodeRef(origPrimaryParent.getParentRef().getStoreRef(), node.getNodeRef().getId()); - - CorrespondingNodeResolver.ResolvedParentChildPair resolvedNodes = nodeResolver.resolveCorrespondingNode( - origNodeRef, origPrimaryParent, node.getParentPath()); - - // Does a corresponding node exist in this repo? - if (resolvedNodes.resolvedChild != null) + NodeRef exNode = resolvedNodes.resolvedChild; + // Yes, it does. Delete it. + if (log.isDebugEnabled()) { - NodeRef exNode = resolvedNodes.resolvedChild; - // Yes, it does. Delete it. - if (log.isDebugEnabled()) - { - log.debug("Incoming deleted noderef " + node.getNodeRef() - + " has been resolved to existing local noderef " + exNode - + " - deleting"); - } - - //TODO : do we have a business rule that only the "from" repo can delete a node? Yes we do. - if(alienProcessor.isAlien(exNode)) - { - logProgress("Pruning local node: " + exNode); - if (log.isDebugEnabled()) - { - log.debug("Node to be deleted is alien prune rather than delete: " + exNode); - } - alienProcessor.pruneNode(exNode, header.getRepositoryId()); - } - else - { - // TODO Need to restrict to the "from" repo Id. - // Not alien - delete it. - logProgress("Deleting local node: " + exNode); - nodeService.deleteNode(exNode); - if (log.isDebugEnabled()) - { - log.debug("Deleted local node: " + exNode); - } - } - } - else - { - logProgress("Unable to find corresponding node for incoming deleted node: " + node.getNodeRef()); - if (log.isDebugEnabled()) - { - log.debug("Incoming deleted noderef has no corresponding local noderef: " + node.getNodeRef() - + " - ignoring"); - } + log.debug("Incoming deleted noderef " + node.getNodeRef() + + " has been resolved to existing local noderef " + exNode + + " - deleting"); } + + delete(exNode); } else { - logProgress("Incoming deleted node is already in the local archive store - ignoring: " + node.getNodeRef()); + logProgress("Unable to find corresponding node for incoming deleted node: " + node.getNodeRef()); + if (log.isDebugEnabled()) + { + log.debug("Incoming deleted noderef has no corresponding local noderef: " + node.getNodeRef() + + " - ignoring"); + } } } @@ -372,6 +344,51 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB // Is the node that we've just added the parent of any orphans that // we've found earlier? checkOrphans(newNode.getChildRef()); + } + + /** + * Delete this node + * @param exNode + */ + protected void delete(NodeRef nodeToDelete) + { + if(alienProcessor.isAlien(nodeToDelete)) + { + logProgress("Pruning local node: " + nodeToDelete); + if (log.isDebugEnabled()) + { + log.debug("Node to be deleted is alien prune rather than delete: " + nodeToDelete); + } + alienProcessor.pruneNode(nodeToDelete, header.getRepositoryId()); + } + else + { + /** + * Check that if the destination is "from" the transferring repo if it is "from" another repo then ignore + */ + if(nodeService.hasAspect(nodeToDelete, TransferModel.ASPECT_TRANSFERRED)) + { + String fromRepository = (String)nodeService.getProperty(nodeToDelete, TransferModel.PROP_FROM_REPOSITORY_ID); + String transferringRepo = header.getRepositoryId(); + + if(fromRepository != null && transferringRepo != null) + { + if(!fromRepository.equalsIgnoreCase(transferringRepo)) + { + logProgress("Not deleting local node (not from the transferring repository): " + nodeToDelete); + return; + } + } + } + + // Not alien or from another repo - delete it. + logProgress("Deleting local node: " + nodeToDelete); + nodeService.deleteNode(nodeToDelete); + if (log.isDebugEnabled()) + { + log.debug("Deleted local node: " + nodeToDelete); + } + } } private void checkOrphans(NodeRef parentNode) @@ -410,7 +427,26 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB ChildAssociationRef primaryParentAssoc) { NodeRef nodeToUpdate = resolvedNodes.resolvedChild; + + /** + * Check that if the destination is "from" the transferring repo if it is "from" another repo then ignore + */ + if(nodeService.hasAspect(nodeToUpdate, TransferModel.ASPECT_TRANSFERRED)) + { + String fromRepository = (String)nodeService.getProperty(nodeToUpdate, TransferModel.PROP_FROM_REPOSITORY_ID); + String transferringRepo = header.getRepositoryId(); + + if(fromRepository != null && transferringRepo != null) + { + if(!fromRepository.equalsIgnoreCase(transferringRepo)) + { + logProgress("Not updating local node (not from the transferring repository): " + node.getNodeRef()); + return; + } + } + } + logProgress("Updating local node: " + node.getNodeRef()); QName parentAssocType = primaryParentAssoc.getTypeQName(); QName parentAssocName = primaryParentAssoc.getQName(); @@ -425,7 +461,8 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB parentAssocType = tempLocation.getTypeQName(); parentAssocName = tempLocation.getQName(); storeOrphanNode(primaryParentAssoc); - } + } + // First of all, do we need to move the node? If any aspect of the // primary parent association has changed // then the answer is "yes" @@ -438,9 +475,9 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB /** * Yes, the parent assoc has changed so we need to move the node */ - // the parent node may no longer be an alien - if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_ALIEN)) + if(nodeService.hasAspect(currentParent.getParentRef(), TransferModel.ASPECT_ALIEN)) { + // old parent node ref may be alien alienProcessor.beforeDeleteAlien(node.getNodeRef()); } diff --git a/source/java/org/alfresco/repo/transfer/RepoTertiaryManifestProcessorImpl.java b/source/java/org/alfresco/repo/transfer/RepoTertiaryManifestProcessorImpl.java index 19686dbb18..ea78c19235 100644 --- a/source/java/org/alfresco/repo/transfer/RepoTertiaryManifestProcessorImpl.java +++ b/source/java/org/alfresco/repo/transfer/RepoTertiaryManifestProcessorImpl.java @@ -19,23 +19,16 @@ package org.alfresco.repo.transfer; -import java.io.Serializable; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.Stack; import org.alfresco.repo.transfer.manifest.TransferManifestDeletedNode; import org.alfresco.repo.transfer.manifest.TransferManifestHeader; -import org.alfresco.repo.transfer.manifest.TransferManifestNodeHelper; import org.alfresco.repo.transfer.manifest.TransferManifestNormalNode; -import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.transfer.TransferReceiver; -import org.alfresco.service.namespace.RegexQNamePattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -53,6 +46,7 @@ public class RepoTertiaryManifestProcessorImpl extends AbstractManifestProcessor { private NodeService nodeService; private AlienProcessor alienProcessor; + CorrespondingNodeResolver nodeResolver; private static final Log log = LogFactory.getLog(RepoTertiaryManifestProcessorImpl.class); @@ -83,38 +77,48 @@ public class RepoTertiaryManifestProcessorImpl extends AbstractManifestProcessor protected void processNode(TransferManifestNormalNode node) { - NodeRef nodeRef = node.getNodeRef(); - log.debug("processNode : " + nodeRef); - if(isSync) + if (log.isDebugEnabled()) { - - List expectedChildren = node.getChildAssocs(); - - List expectedChildNodeRefs = new ArrayList(); - - for(ChildAssociationRef ref : expectedChildren) - { - if(log.isDebugEnabled()) - { - log.debug("expecting child" + ref); - } - expectedChildNodeRefs.add(ref.getChildRef()); - } - + log.debug("Processing node with incoming noderef of " + node.getNodeRef()); + } + logProgress("Processing incoming node: " + node.getNodeRef() + " -- Source path = " + node.getParentPath() + "/" + node.getPrimaryParentAssoc().getQName()); - // TODO Do we need to worry about path based nodes ? Assuming no at the moment. + + /** + * This processor only does processes sync requests. + */ + if(isSync) + { + ChildAssociationRef primaryParentAssoc = node.getPrimaryParentAssoc(); + + CorrespondingNodeResolver.ResolvedParentChildPair resolvedNodes = nodeResolver.resolveCorrespondingNode(node + .getNodeRef(), primaryParentAssoc, node.getParentPath()); + + NodeRef nodeRef = resolvedNodes.resolvedChild; + if(nodeService.exists(nodeRef)) { - log.debug("destination node exists"); + log.debug("destination node exists - check the children"); + + //TODO Use more efficient query here. + List expectedChildren = node.getChildAssocs(); + + List expectedChildNodeRefs = new ArrayList(); + + for(ChildAssociationRef ref : expectedChildren) + { + if(log.isDebugEnabled()) + { + log.debug("expecting child node" + ref); + } + expectedChildNodeRefs.add(ref.getChildRef()); + } - /** - * yes this node exists in the destination. - */ List actualChildren = nodeService.getChildAssocs(nodeRef); /** - * For each destination child association + * For each actual child association */ for(ChildAssociationRef child : actualChildren) { @@ -131,46 +135,56 @@ public class RepoTertiaryManifestProcessorImpl extends AbstractManifestProcessor { /** * An unexpected child - if this node has been transferred then - * it needs to be deleted. + * it may need to be deleted. * - * another repository then we have to prune the alien children + * If from another repository then we have to prune the alien children * rather than deleting it. */ - log.debug("an unexpected child node:" + child); if(nodeService.hasAspect(childNodeRef, TransferModel.ASPECT_TRANSFERRED)) { + log.debug("an unexpected transferred child node:" + child); String fromRepositoryId = (String)nodeService.getProperty(childNodeRef, TransferModel.PROP_FROM_REPOSITORY_ID); // Yes this is a transferred node. When syncing we only delete nodes that are "from" // the system that is transferring to this repo. if(fromRepositoryId != null && manifestRepositoryId != null) { - if(manifestRepositoryId.equalsIgnoreCase(fromRepositoryId)) + if(nodeService.hasAspect(childNodeRef, TransferModel.ASPECT_ALIEN)) { - // Yes the manifest repository Id and the from repository Id match. - if(nodeService.hasAspect(childNodeRef, TransferModel.ASPECT_ALIEN)) + /** + * This node can't be deleted since it contains alien content + * it needs to be "pruned" of the transferring repo's content instead. + */ + log.debug("node to be deleted contains alien content so needs to be pruned." + childNodeRef); + alienProcessor.pruneNode(childNodeRef, fromRepositoryId); + } + else + { + // Node + log.debug("node not alien"); + if(manifestRepositoryId.equalsIgnoreCase(fromRepositoryId)) { - /** - * This node can't be deleted since it contains alien content - * it needs to be "pruned" of the transferring repo's content instead. - */ - log.debug("node to be deleted contains alien content so needs to be pruned." + childNodeRef); - alienProcessor.pruneNode(childNodeRef, fromRepositoryId); - //pruneNode(childNodeRef, fromRepositoryId); - } - else - { - // Destination node needs to be deleted. + // Yes the manifest repository Id and the from repository Id match. + // Destination node if from the transferring repo and needs to be deleted. nodeService.deleteNode(childNodeRef); log.debug("deleted node:" + childNodeRef); } } - } + } + else + { + log.debug("node does not have a transferred aspect"); + } } } } } } + + else + { + log.debug("not sync mode - do nothing"); + } } } @@ -202,161 +216,6 @@ public class RepoTertiaryManifestProcessorImpl extends AbstractManifestProcessor this.nodeService = nodeService; } -// /** -// * Prune out the non aliens from the specified repository -// * -// * Need to walk the tree downwards pruning any aliens for this repository -// * -// * Also any folders remaining need to have their invaded by field rippled upwards since they may no -// * longer be invaded by the specified repository if all the alien children have been pruned. -// * -// * @param nodeRef the node to prune -// * @param fromRepositoryId the repository id of the nodes to prune. -// */ -// private void pruneNode(NodeRef parentNodeRef, String fromRepositoryId) -// { -// Stack nodesToPrune = new Stack(); -// Stack foldersToRecalculate = new Stack(); -// nodesToPrune.add(parentNodeRef); -// -// while(!nodesToPrune.isEmpty()) -// { -// /** -// * for all alien children -// * -// * if from the repo with no (other) aliens - delete -// * -// * if from the repo with multiple alien invasions - leave alone but process children -// */ -// NodeRef currentNodeRef = nodesToPrune.pop(); -// -// log.debug("pruneNode:" + currentNodeRef); -// -// if(nodeService.hasAspect(currentNodeRef, TransferModel.ASPECT_ALIEN)) -// { -// // Yes this is an alien node -// ListinvadedBy = (List)nodeService.getProperty(currentNodeRef, TransferModel.PROP_INVADED_BY); -// if(invadedBy.contains(fromRepositoryId)) -// { -// if(invadedBy.size() == 1) -// { -// // we are invaded by a single repository which must be fromRepositoryId -// log.debug("pruned - deleted node:" + currentNodeRef); -// nodeService.deleteNode(currentNodeRef); -// } -// else -// { -// log.debug("folder has multiple invaders"); -// // multiple invasion - so it must be a folder -// //TODO replace with a more efficient query -// List refs = nodeService.getChildAssocs(parentNodeRef); -// for(ChildAssociationRef ref : refs) -// { -// if(log.isDebugEnabled()) -// { -// log.debug("will need to check child:" + ref); -// } -// nodesToPrune.push(ref.getChildRef()); -// -// /** -// * This folder can't be deleted so its invaded flag needs to be re-calculated -// */ -// if(!foldersToRecalculate.contains(ref.getParentRef())) -// { -// foldersToRecalculate.push(ref.getParentRef()); -// } -// } -// } -// } -// else -// { -// /** -// * Current node has been invaded by another repository -// * -// * Need to check fromRepositoryId since its children may need to be pruned -// */ -// nodeService.hasAspect(currentNodeRef, TransferModel.ASPECT_TRANSFERRED); -// { -// String fromRepoId = (String)nodeService.getProperty(currentNodeRef, TransferModel.PROP_FROM_REPOSITORY_ID); -// if(fromRepositoryId.equalsIgnoreCase(fromRepoId)) -// { -// log.debug("folder is from the transferring repository"); -// // invaded from somewhere else - so it must be a folder -// List refs = nodeService.getChildAssocs(currentNodeRef); -// for(ChildAssociationRef ref : refs) -// { -// if(log.isDebugEnabled()) -// { -// log.debug("will need to check child:" + ref); -// } -// nodesToPrune.push(ref.getChildRef()); -// -// /** -// * This folder can't be deleted so its invaded flag needs to be re-calculated -// */ -// if(!foldersToRecalculate.contains(ref.getParentRef())) -// { -// foldersToRecalculate.push(ref.getParentRef()); -// } -// } -// } -// } -// } -// } -// else -// { -// // Current node does not contain alien nodes so it can be deleted. -// nodeService.hasAspect(currentNodeRef, TransferModel.ASPECT_TRANSFERRED); -// { -// String fromRepoId = (String)nodeService.getProperty(currentNodeRef, TransferModel.PROP_FROM_REPOSITORY_ID); -// if(fromRepositoryId.equalsIgnoreCase(fromRepoId)) -// { -// // we are invaded by a single repository -// log.debug("pruned - deleted non alien node:" + currentNodeRef); -// nodeService.deleteNode(currentNodeRef); -// } -// } -// } -// } -// -// /** -// * Now ripple the "invadedBy" flag upwards. -// */ -// -// while(!foldersToRecalculate.isEmpty()) -// { -// NodeRef folderNodeRef = foldersToRecalculate.pop(); -// -// log.debug("recalculate invadedBy :" + folderNodeRef); -// -// ListfolderInvadedBy = (List)nodeService.getProperty(folderNodeRef, TransferModel.PROP_INVADED_BY); -// -// boolean stillInvaded = false; -// //TODO need a more efficient query here -// List refs = nodeService.getChildAssocs(folderNodeRef); -// for(ChildAssociationRef ref : refs) -// { -// NodeRef childNode = ref.getChildRef(); -// ListchildInvadedBy = (List)nodeService.getProperty(childNode, TransferModel.PROP_INVADED_BY); -// -// if(childInvadedBy.contains(fromRepositoryId)) -// { -// log.debug("folder is still invaded"); -// stillInvaded = true; -// break; -// } -// } -// -// if(!stillInvaded) -// { -// List newInvadedBy = new ArrayList(folderInvadedBy); -// folderInvadedBy.remove(fromRepositoryId); -// nodeService.setProperty(folderNodeRef, TransferModel.PROP_INVADED_BY, (Serializable)newInvadedBy); -// } -// } -// log.debug("pruneNode: end"); -// } - public void setAlienProcessor(AlienProcessor alienProcessor) { this.alienProcessor = alienProcessor; @@ -366,4 +225,13 @@ public class RepoTertiaryManifestProcessorImpl extends AbstractManifestProcessor { return alienProcessor; } + + /** + * @param nodeResolver + * the nodeResolver to set + */ + public void setNodeResolver(CorrespondingNodeResolver nodeResolver) + { + this.nodeResolver = nodeResolver; + } } diff --git a/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImpl.java b/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImpl.java index edcf1ec898..c8e973fe53 100644 --- a/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImpl.java +++ b/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImpl.java @@ -968,75 +968,7 @@ public class RepoTransferReceiverImpl implements TransferReceiver, log.debug("on create child association to transferred node"); final String localRepositoryId = descriptorService.getCurrentRepositoryDescriptor().getId(); - alienProcessor.onCreateChild(childAssocRef, localRepositoryId); -// -// ChildAssociationRef currentAssoc = childAssocRef; -// -// final String localRepositoryId = descriptorService.getCurrentRepositoryDescriptor().getId(); -// -// // TODO Needs to check assoc is a cm:contains or subtype -// if(childAssocRef.isPrimary()) -// { -// NodeRef parentNodeRef = currentAssoc.getParentRef(); -// NodeRef childNodeRef = currentAssoc.getChildRef(); -// -// /** -// * Make the new child node ref an alien node -// */ -// setAlien(childNodeRef, localRepositoryId); -// -// /** -// * Now deal with the parents of this alien node -// */ -// while(currentAssoc != null) -// { -// parentNodeRef = currentAssoc.getParentRef(); -// childNodeRef = currentAssoc.getChildRef(); -// -// if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED) || nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_ALIEN)) -// { -// if (!isInvaded(parentNodeRef, localRepositoryId)) -// { -// if(log.isDebugEnabled()) -// { -// log.debug("alien invades parent node:" + parentNodeRef + ", repositoryId:" + localRepositoryId); -// } -// -// final NodeRef newAlien = parentNodeRef; -// -// /** -// * Parent may be locked or not be editable by the current user -// * turn off auditing and lock service for this transaction and -// * run as admin. -// */ -// RunAsWork actionRunAs = new RunAsWork() -// { -// public Void doWork() throws Exception -// { -// behaviourFilter.disableBehaviour(newAlien, ContentModel.ASPECT_AUDITABLE); -// behaviourFilter.disableBehaviour(newAlien, ContentModel.ASPECT_LOCKABLE); -// setAlien(newAlien, localRepositoryId); -// return null; -// } -// }; -// AuthenticationUtil.runAs(actionRunAs, AuthenticationUtil.getSystemUserName()); -// -// // Yes the parent has been invaded so step up to the parent's parent -// currentAssoc = nodeService.getPrimaryParent(parentNodeRef); -// } -// else -// { -// log.debug("parent node is already invaded"); -// currentAssoc = null; -// } -// } -// else -// { -// log.debug("parent is not a transferred node"); -// currentAssoc = null; -// } -// } -// } + alienProcessor.onCreateChild(childAssocRef, localRepositoryId); } /** @@ -1048,175 +980,8 @@ public class RepoTransferReceiverImpl implements TransferReceiver, { log.debug("on delete node - need to check for transferred node"); alienProcessor.beforeDeleteAlien(deletedNodeRef); -// -// Liststuff = (List)nodeService.getProperty(deletedNodeRef, TransferModel.PROP_INVADED_BY); -// -// Vector exInvaders = new Vector(stuff); -// -// ChildAssociationRef currentAssoc = nodeService.getPrimaryParent(deletedNodeRef); -// -// while(currentAssoc != null && exInvaders != null && exInvaders.size() > 0) -// { -// NodeRef parentNodeRef = currentAssoc.getParentRef(); -// NodeRef currentNodeRef = currentAssoc.getChildRef(); -// -// /** -// * Does the parent have alien invaders ? -// */ -// if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_ALIEN)) -// { -// log.debug("parent node is alien - check siblings"); -// -// /** -// * For each invader of the deletedNode -// */ -// Iterator i = exInvaders.listIterator(); -// while(i.hasNext()) -// { -// String exInvader = i.next(); -// log.debug("Checking exInvader:" + exInvader); -// -// /** -// * Check the siblings of this node to see whether there are any other alien nodes for this invader. -// */ -// //TODO replace with a more efficient query -// List refs = nodeService.getChildAssocs(parentNodeRef); -// -// for(ChildAssociationRef ref : refs) -// { -// NodeRef childRef = ref.getChildRef(); -// ListinvadedBy = (List)nodeService.getProperty(childRef, TransferModel.PROP_INVADED_BY); -// -// if(childRef.equals(currentNodeRef)) -// { -// // do nothing - this is the node we are working with. -// } -// else -// { -// if(invadedBy != null && invadedBy.contains(exInvader)) -// { -// // There is a sibling so remove this from the list of ex invaders. -// log.debug("yes there is a sibling so it remains an invader"); -// i.remove(); -// break; -// } -// } -// } // for each child assoc -// -// } // for each invader -// -// log.debug("end of checking siblings"); -// -// if(exInvaders.size() > 0) -// { -// log.debug("removing invaders from parent node:" + parentNodeRef); -// List parentInvaders = (List)nodeService.getProperty(parentNodeRef, TransferModel.PROP_INVADED_BY); -// -// final List newInvaders = new ArrayList(10); -// for(String invader : parentInvaders) -// { -// if(exInvaders.contains(invader)) -// { -// log.debug("removing invader:" + invader); -// } -// else -// { -// newInvaders.add(invader); -// } -// } -// -// final NodeRef oldAlien = parentNodeRef; -// -// /** -// * Parent may be locked or not be editable by the current user -// * turn off auditing and lock service for this transaction and -// * run as admin. -// */ -// RunAsWork actionRunAs = new RunAsWork() -// { -// public Void doWork() throws Exception -// { -// behaviourFilter.disableBehaviour(oldAlien, ContentModel.ASPECT_AUDITABLE); -// behaviourFilter.disableBehaviour(oldAlien, ContentModel.ASPECT_LOCKABLE); -// if(newInvaders.size() > 0) -// { -// nodeService.setProperty(oldAlien, TransferModel.PROP_INVADED_BY, (Serializable)newInvaders); -// } -// else -// { -// log.debug("parent node no is no longer alien"); -// nodeService.removeAspect(oldAlien, TransferModel.ASPECT_ALIEN); -// } -// return null; -// } -// }; -// AuthenticationUtil.runAs(actionRunAs, AuthenticationUtil.getSystemUserName()); -// } -// -// /** -// * Now step up to the parent's parent -// */ -// currentAssoc = nodeService.getPrimaryParent(parentNodeRef); -// } -// else -// { -// log.debug("parent is not an alien node"); -// currentAssoc = null; -// } -// } // end of while } - -// /** -// * Is this node invaded ? -// * @param nodeRef -// * @param invader -// * @return true, this node has been invaded by the invader -// */ -// private boolean isInvaded(NodeRef nodeRef, String invader) -// { -// ListinvadedBy = (List)nodeService.getProperty(nodeRef, TransferModel.PROP_INVADED_BY); -// -// if(invadedBy == null) -// { -// return false; -// } -// -// return invadedBy.contains(invader); -// } -// -// /** -// * Mark the specified node as an alien node, invadedby the invader. -// * @param newAlien -// * @param invader -// */ -// private void setAlien(NodeRef newAlien, String invader) -// { -// // Introduce a Multi-valued property -// List invadedBy = (List)nodeService.getProperty(newAlien, -// TransferModel.PROP_INVADED_BY); -// -// if(invadedBy == null) -// { -// nodeService.setProperty(newAlien, TransferModel.PROP_ALIEN, Boolean.TRUE); -// invadedBy = new ArrayList(1); -// } -// invadedBy.add(invader); -// -// /** -// * Set the invaded by property -// */ -// nodeService.setProperty(newAlien, TransferModel.PROP_INVADED_BY, (Serializable) invadedBy); -// -// /** -// * Experiment with a residual property -// */ -// nodeService.setProperty(newAlien, QName.createQName(TransferModel.TRANSFER_MODEL_1_0_URI, -// "invader" + invader), Boolean.TRUE); -// -// } - - - + public void setDescriptorService(DescriptorService descriptorService) { this.descriptorService = descriptorService; diff --git a/source/java/org/alfresco/repo/transfer/TransferModel.java b/source/java/org/alfresco/repo/transfer/TransferModel.java index f1e55163be..7eac695404 100644 --- a/source/java/org/alfresco/repo/transfer/TransferModel.java +++ b/source/java/org/alfresco/repo/transfer/TransferModel.java @@ -45,7 +45,7 @@ public interface TransferModel */ static final QName ASPECT_ALIEN = QName.createQName(TRANSFER_MODEL_1_0_URI, "alien"); static final QName PROP_INVADED_BY = QName.createQName(TRANSFER_MODEL_1_0_URI, "invadedBy"); - static final QName PROP_ALIEN = QName.createQName(TRANSFER_MODEL_1_0_URI, "alien"); +// static final QName PROP_ALIEN = QName.createQName(TRANSFER_MODEL_1_0_URI, "alien"); /* * Type : Transfer Group diff --git a/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java b/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java index 923af3f49a..605e8fc839 100644 --- a/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java +++ b/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java @@ -22,6 +22,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.ArrayList; +import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.List; @@ -101,8 +102,6 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest private PersonService personService; private DescriptorService descriptorService; - - String COMPANY_HOME_XPATH_QUERY = "/{http://www.alfresco.org/model/application/1.0}company_home"; String GUEST_HOME_XPATH_QUERY = "/{http://www.alfresco.org/model/application/1.0}company_home/{http://www.alfresco.org/model/application/1.0}guest_home"; @@ -599,7 +598,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest } /** - * Test the transfer method by sending one node. + * Test the transfer method by sending one node (CRUD). * * Step 1: Create a new node (No content) * transfer @@ -612,8 +611,10 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest * * Step 4: Transfer again * transfer (Should transfer but not request the content item) + * + * Step 5: Delete the node * - * Step 5: Negative test : transfer no nodes + * Step 6: Negative test : transfer no nodes * transfer (should throw exception) * * This is a unit test so it does some shenanigans to send to the same instance of alfresco. @@ -858,7 +859,49 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest } /** - * Step 5 + * Step 5 + * Delete the node through transfer of the archive node + */ + logger.debug("Transfer again - with no new content"); + startNewTransaction(); + try + { + nodeService.deleteNode(contentNodeRef); + } + finally + { + endTransaction(); + } + + NodeRef deletedContentNodeRef = new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, contentNodeRef.getId()); + + startNewTransaction(); + try + { + TransferDefinition definition = new TransferDefinition(); + Setnodes = new HashSet(); + nodes.add(deletedContentNodeRef); + definition.setNodes(nodes); + transferService.transfer(targetName, definition); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + assertFalse("dest node still exists", nodeService.exists(destNodeRef)); + } + finally + { + endTransaction(); + } + + + /** + * Step 6 * Negative test transfer nothing */ logger.debug("Transfer again - with no content - should throw exception"); @@ -870,9 +913,10 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest } catch(TransferException te) { - // expect to go here + // expect to go here } - } + + } /** * Test the transfer method by sending a graph of nodes. @@ -3011,7 +3055,6 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest assertTrue("dest node ref does not exist", nodeService.exists(A1destNodeRef)); // Check injected transferred aspect. - assertTrue("node A1 is not alien prop", (Boolean)nodeService.getProperty(A1destNodeRef, TransferModel.PROP_ALIEN)); assertTrue("node A1 is not alien aspect", (Boolean)nodeService.hasAspect(A1destNodeRef, TransferModel.ASPECT_ALIEN)); assertNotNull("repository id is null", (String)nodeService.getProperty(A1destNodeRef, TransferModel.PROP_REPOSITORY_ID)); assertNotNull("from repository id is null", (String)nodeService.getProperty(A1destNodeRef, TransferModel.PROP_FROM_REPOSITORY_ID)); @@ -3091,10 +3134,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest // Now validate that the target node exists and has similar properties to the source NodeRef A1destNodeRef = testNodeFactory.getMappedNodeRef(A1NodeRef); NodeRef A2destNodeRef = testNodeFactory.getMappedNodeRef(A2NodeRef); - - assertTrue("node A1 is not alien", (Boolean)nodeService.getProperty(A1destNodeRef, TransferModel.PROP_ALIEN)); - assertTrue("node A2 is not alien", (Boolean)nodeService.getProperty(A2destNodeRef, TransferModel.PROP_ALIEN)); - + assertTrue("node A1 is not alien aspect", (Boolean)nodeService.hasAspect(A1destNodeRef, TransferModel.ASPECT_ALIEN)); assertTrue("node A2 is not alien aspect", (Boolean)nodeService.hasAspect(A2destNodeRef, TransferModel.ASPECT_ALIEN)); } @@ -3451,6 +3491,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest } } + /** * Test the transfer method with regard to permissions on a node. *

@@ -4485,17 +4526,14 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest try { nodeService.setProperty(A1NodeRef, ContentModel.PROP_TITLE, NEW_TITLE); - nodeService.setProperty(A1NodeRef, TransferModel.PROP_ALIEN, Boolean.FALSE); nodeService.setProperty(A1NodeRef, TransferModel.PROP_FROM_REPOSITORY_ID, REPO_ID_B); nodeService.setProperty(A1NodeRef, TransferModel.PROP_REPOSITORY_ID, REPO_ID_B); nodeService.setProperty(A2NodeRef, ContentModel.PROP_TITLE, NEW_TITLE); - nodeService.setProperty(A2NodeRef, TransferModel.PROP_ALIEN, Boolean.FALSE); nodeService.setProperty(A2NodeRef, TransferModel.PROP_FROM_REPOSITORY_ID, REPO_ID_B); nodeService.setProperty(A2NodeRef, TransferModel.PROP_REPOSITORY_ID, REPO_ID_B); nodeService.setProperty(A3NodeRef, ContentModel.PROP_TITLE, NEW_TITLE); - nodeService.setProperty(A3NodeRef, TransferModel.PROP_ALIEN, Boolean.FALSE); nodeService.setProperty(A3NodeRef, TransferModel.PROP_FROM_REPOSITORY_ID, REPO_ID_B); nodeService.setProperty(A3NodeRef, TransferModel.PROP_REPOSITORY_ID, REPO_ID_B); @@ -4507,7 +4545,6 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest nodeService.setProperty(A7NodeRef, ContentModel.PROP_TITLE, NEW_TITLE); nodeService.setProperty(A7NodeRef, ContentModel.PROP_NAME, "A7"); nodeService.setProperty(A7NodeRef, ContentModel.PROP_TITLE, NEW_TITLE); - nodeService.setProperty(A7NodeRef, TransferModel.PROP_ALIEN, Boolean.FALSE); nodeService.setProperty(A7NodeRef, TransferModel.PROP_FROM_REPOSITORY_ID, REPO_ID_B); nodeService.setProperty(A7NodeRef, TransferModel.PROP_REPOSITORY_ID, REPO_ID_B); @@ -4562,75 +4599,51 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest * This is a unit test so does lots of shenanigans to fake transfer from three repositories on a single repo. * * Trees of nodes - * - * A1 - * | - * images + *

+     *      A1              B1               C1
+     *      |                                 |    
+     *    A2/images                       A2 Dummy/images
+     *      |                              |
+     *      A3                            C3 
+     *                                          
+     * Destination   
+     *      B1
      *      |
-     *      A2
-     *
-     *      B
-     *      |
-     *    images
-     *      |
-     *      B2
-     *    
-     *      C1
-     *      |
-     *    images
-     *      |
-     *      C2    
-     *         
-     * 
+     *    A2/images
+     *      |     |
+     *      C3    A3 
+     *            | 
+     *            C4         
+     * 
+ * Step 1. Transfer from A to B. + * Step 2. Transfer from C to B (crossing over on A2Dest) + * Step 3. Invade A3Dest via C + * Step 4. Delete C4. Sync from C + * Step 5. Delete C3 - A2 dest images folder uninvaded. + */ - public void testMultiRepoSync() throws Exception + public void testMultiRepoTransfer() throws Exception { - /** - * Step 1 - * create DesTree A1...A6 - * transfer (sync) - * check the transfered aspect - * create node B6. Fake its transfered aspect to be from Repo B, Non Alien. - * transfer (sync) - */ setDefaultRollback(false); String CONTENT_TITLE = "ContentTitle"; String CONTENT_TITLE_UPDATED = "ContentTitleUpdated"; Locale CONTENT_LOCALE = Locale.GERMAN; String CONTENT_STRING = "Hello"; - - /** - * For unit test - * - replace the HTTP transport with the in-process transport - * - replace the node factory with one that will map node refs, paths etc. - */ - TransferTransmitter transmitter = new UnitTestInProcessTransmitterImpl(receiver, contentService, transactionService); - transferServiceImpl.setTransmitter(transmitter); - UnitTestTransferManifestNodeFactory testNodeFactory = new UnitTestTransferManifestNodeFactory(this.transferManifestNodeFactory); - transferServiceImpl.setTransferManifestNodeFactory(testNodeFactory); - List> pathMap = testNodeFactory.getPathMap(); - // Map company_home/guest_home to company_home so tranferred nodes and moved "up" one level. - pathMap.add(new Pair(PathHelper.stringToPath(GUEST_HOME_XPATH_QUERY), PathHelper.stringToPath(COMPANY_HOME_XPATH_QUERY))); - - DescriptorService mockedDescriptorService = getMockDescriptorService(REPO_ID_A); - transferServiceImpl.setDescriptorService(mockedDescriptorService); - - String repositoryId = REPO_ID_A; - - /** - * Now go ahead and create our first transfer target - */ - String targetName = "testTransferSyncNodes"; + + String targetName = "testMultiRepoTransfer"; TransferTarget transferMe; + NodeRef S0NodeRef; NodeRef A1NodeRef; NodeRef A2NodeRef; NodeRef A3NodeRef; - NodeRef A4NodeRef; - NodeRef A5NodeRef; - NodeRef B6NodeRef; - NodeRef A7NodeRef; - + NodeRef B1NodeRef; + NodeRef C1NodeRef; + NodeRef C2NodeRef; + NodeRef C3NodeRef; + NodeRef C4NodeRef; + NodeRef A3Dummy; + startNewTransaction(); try { @@ -4642,60 +4655,89 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest assertEquals("", 1, guestHomeResult.length()); NodeRef guestHome = guestHomeResult.getNodeRef(0); - /** - * Create a test nodes A1 through A5 that we will read and write - */ { - // Node A1 + /** + * Node Source - located under guest home + */ String name = GUID.generate(); ChildAssociationRef child = nodeService.createNode(guestHome, ContentModel.ASSOC_CONTAINS, QName.createQName(name), ContentModel.TYPE_FOLDER); - A1NodeRef = child.getChildRef(); - nodeService.setProperty(A1NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); - nodeService.setProperty(A1NodeRef, ContentModel.PROP_NAME, name); + S0NodeRef = child.getChildRef(); + nodeService.setProperty(S0NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); + nodeService.setProperty(S0NodeRef, ContentModel.PROP_NAME, name); } + { + // Node A1 + ChildAssociationRef child = nodeService.createNode(S0NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A1"), ContentModel.TYPE_FOLDER); + A1NodeRef = child.getChildRef(); + nodeService.setProperty(A1NodeRef, ContentModel.PROP_TITLE, "A1"); + nodeService.setProperty(A1NodeRef, ContentModel.PROP_NAME, "A1"); + } + { // Node A2 - ChildAssociationRef child = nodeService.createNode(A1NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A2"), ContentModel.TYPE_FOLDER); + ChildAssociationRef child = nodeService.createNode(A1NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("images"), ContentModel.TYPE_FOLDER); A2NodeRef = child.getChildRef(); - nodeService.setProperty(A2NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); - nodeService.setProperty(A2NodeRef, ContentModel.PROP_NAME, "A2"); + nodeService.setProperty(A2NodeRef, ContentModel.PROP_TITLE, "images"); + nodeService.setProperty(A2NodeRef, ContentModel.PROP_NAME, "images"); } { // Node A3 - ChildAssociationRef child = nodeService.createNode(A1NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A3"), ContentModel.TYPE_CONTENT); + ChildAssociationRef child = nodeService.createNode(A2NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A3"), ContentModel.TYPE_FOLDER); A3NodeRef = child.getChildRef(); - nodeService.setProperty(A3NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); + nodeService.setProperty(A3NodeRef, ContentModel.PROP_TITLE, "A3"); nodeService.setProperty(A3NodeRef, ContentModel.PROP_NAME, "A3"); - - ContentWriter writer = contentService.getWriter(A3NodeRef, ContentModel.PROP_CONTENT, true); - writer.setLocale(CONTENT_LOCALE); - writer.putContent(CONTENT_STRING); } + { - // Node A4 - ChildAssociationRef child = nodeService.createNode(A2NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A4"), ContentModel.TYPE_CONTENT); - A4NodeRef = child.getChildRef(); - nodeService.setProperty(A4NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); - nodeService.setProperty(A4NodeRef, ContentModel.PROP_NAME, "A4"); - - ContentWriter writer = contentService.getWriter(A4NodeRef, ContentModel.PROP_CONTENT, true); - writer.setLocale(CONTENT_LOCALE); - writer.putContent(CONTENT_STRING); + // Node B1 + ChildAssociationRef child = nodeService.createNode(S0NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B1"), ContentModel.TYPE_FOLDER); + B1NodeRef = child.getChildRef(); + nodeService.setProperty(B1NodeRef, ContentModel.PROP_TITLE, "B1"); + nodeService.setProperty(B1NodeRef, ContentModel.PROP_NAME, "B1"); } + { - // Node A5 - ChildAssociationRef child = nodeService.createNode(A2NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A5"), ContentModel.TYPE_CONTENT); - A5NodeRef = child.getChildRef(); - nodeService.setProperty(A5NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); - nodeService.setProperty(A5NodeRef, ContentModel.PROP_NAME, "A5"); - - ContentWriter writer = contentService.getWriter(A5NodeRef, ContentModel.PROP_CONTENT, true); - writer.setLocale(CONTENT_LOCALE); - writer.putContent(CONTENT_STRING); + // Node C1 + ChildAssociationRef child = nodeService.createNode(S0NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("C1"), ContentModel.TYPE_FOLDER); + C1NodeRef = child.getChildRef(); + nodeService.setProperty(C1NodeRef, ContentModel.PROP_TITLE, "C1"); + nodeService.setProperty(C1NodeRef, ContentModel.PROP_NAME, "C1"); } - + + { + // Node C2/images + ChildAssociationRef child = nodeService.createNode(C1NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("images"), ContentModel.TYPE_FOLDER); + C2NodeRef = child.getChildRef(); + nodeService.setProperty(C2NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); + nodeService.setProperty(C2NodeRef, ContentModel.PROP_NAME, "images"); + } + + { + // Node C3 + ChildAssociationRef child = nodeService.createNode(C2NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("C3"), ContentModel.TYPE_FOLDER); + C3NodeRef = child.getChildRef(); + nodeService.setProperty(C3NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); + nodeService.setProperty(C3NodeRef, ContentModel.PROP_NAME, "C3"); + } + + { + // Node A3 (Dummy) + ChildAssociationRef child = nodeService.createNode(C2NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A3"), ContentModel.TYPE_FOLDER); + A3Dummy = child.getChildRef(); + nodeService.setProperty(A3Dummy, ContentModel.PROP_TITLE, CONTENT_TITLE); + nodeService.setProperty(A3Dummy, ContentModel.PROP_NAME, "A3 Dummy"); + } + + { + // Node C4 + ChildAssociationRef child = nodeService.createNode(A3Dummy, ContentModel.ASSOC_CONTAINS, QName.createQName("C4"), ContentModel.TYPE_FOLDER); + C4NodeRef = child.getChildRef(); + nodeService.setProperty(C4NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); + nodeService.setProperty(C4NodeRef, ContentModel.PROP_NAME, "C4"); + } + // Create the transfer target if it does not already exist if(!transferService.targetExists(targetName)) { @@ -4711,78 +4753,37 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest endTransaction(); } - Setnodes = new HashSet(); - nodes.add(A1NodeRef); - nodes.add(A2NodeRef); - nodes.add(A3NodeRef); - nodes.add(A4NodeRef); - nodes.add(A5NodeRef); - /** - * transfer (sync) - * check the transfered aspect - * create node B6. Fake its transfered aspect to be from Repo B, Non Alien. - * transfer (sync) - */ - startNewTransaction(); - try - { - { - TransferDefinition definition = new TransferDefinition(); - definition.setNodes(nodes); - definition.setSync(true); - transferService.transfer(targetName, definition); - } - } - finally - { - endTransaction(); - } - startNewTransaction(); - try - { - // Node B6 - faked transfer from repository B. Child of Destination node A1 - NodeRef a1Dest = testNodeFactory.getMappedNodeRef(A1NodeRef); - - assertTrue("dest node A does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(A1NodeRef))); - assertEquals("dest node A1 From RepositoryId", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A1NodeRef), TransferModel.PROP_FROM_REPOSITORY_ID), repositoryId); - assertEquals("dest node A1 Repository Id", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A1NodeRef), TransferModel.PROP_REPOSITORY_ID), repositoryId); - assertEquals("dest node A2 From RepositoryId", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A2NodeRef), TransferModel.PROP_FROM_REPOSITORY_ID), repositoryId); - assertEquals("dest node A2 Repository Id", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A2NodeRef), TransferModel.PROP_REPOSITORY_ID), repositoryId); - assertEquals("dest node A3 From RepositoryId", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A3NodeRef), TransferModel.PROP_FROM_REPOSITORY_ID), repositoryId); - assertEquals("dest node A3 Repository Id", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A3NodeRef), TransferModel.PROP_REPOSITORY_ID), repositoryId); - assertEquals("dest node A4 From RepositoryId", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A4NodeRef), TransferModel.PROP_FROM_REPOSITORY_ID), repositoryId); - assertEquals("dest node A4 Repository Id", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A4NodeRef), TransferModel.PROP_REPOSITORY_ID), repositoryId); - assertEquals("dest node A5 From RepositoryId", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A5NodeRef), TransferModel.PROP_FROM_REPOSITORY_ID), repositoryId); - assertEquals("dest node A5 Repository Id", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A5NodeRef), TransferModel.PROP_REPOSITORY_ID), repositoryId); - - ChildAssociationRef child = nodeService.createNode(a1Dest, ContentModel.ASSOC_CONTAINS, QName.createQName("B6"), ContentModel.TYPE_CONTENT); - B6NodeRef = child.getChildRef(); - nodeService.setProperty(B6NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); - nodeService.setProperty(B6NodeRef, ContentModel.PROP_NAME, "B6"); - - /** - * The first tranfer was mocked to repository A - this is repository B. - */ - - // This is repository B so there's no need to fake it -// nodeService.setProperty(B6NodeRef, TransferModel.PROP_FROM_REPOSITORY_ID, REPO_ID_B); -// nodeService.setProperty(B6NodeRef, TransferModel.PROP_REPOSITORY_ID, REPO_ID_B); - - ContentWriter writer = contentService.getWriter(B6NodeRef, ContentModel.PROP_CONTENT, true); - writer.setLocale(CONTENT_LOCALE); - writer.putContent(CONTENT_STRING); - - } - finally - { - endTransaction(); - } + * For unit test + * - replace the HTTP transport with the in-process transport + * - Map path from A1 to B1 (So transfer will transfer by path) + * - Map path from C1 to B1 + */ + TransferTransmitter transmitter = new UnitTestInProcessTransmitterImpl(receiver, contentService, transactionService); + transferServiceImpl.setTransmitter(transmitter); + UnitTestTransferManifestNodeFactory testNodeFactory = new UnitTestTransferManifestNodeFactory(this.transferManifestNodeFactory); + transferServiceImpl.setTransferManifestNodeFactory(testNodeFactory); + List> pathMap = testNodeFactory.getPathMap(); + // Map Project A/images to Project B/images + // Map Project C/images to Project A/images + nodeService.getPath(A2NodeRef); + pathMap.add(new Pair(nodeService.getPath(A1NodeRef), nodeService.getPath(B1NodeRef))); + pathMap.add(new Pair(nodeService.getPath(C1NodeRef), nodeService.getPath(B1NodeRef))); + DescriptorService mockedDescriptorService = getMockDescriptorService(REPO_ID_A); + transferServiceImpl.setDescriptorService(mockedDescriptorService); + /** + * Step 1 + * Now transfer in A's nodes to Repo B + */ startNewTransaction(); try { TransferDefinition definition = new TransferDefinition(); + Collection nodes = new ArrayList(); + nodes.add(A1NodeRef); + nodes.add(A2NodeRef); + nodes.add(A3NodeRef); definition.setNodes(nodes); definition.setSync(true); transferService.transfer(targetName, definition); @@ -4795,68 +4796,37 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest startNewTransaction(); try { - // Does node B6 still exist ? - assertTrue("dest node B6 does not exist", nodeService.exists(B6NodeRef)); - assertTrue("B6 not alien", nodeService.hasAspect(B6NodeRef, TransferModel.ASPECT_ALIEN)); + assertTrue("dest node A2 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(A2NodeRef))); + assertTrue("dest node A3 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(A3NodeRef))); + + // Check that A3 dest is a child of A2Dest which is a child of B1 + ChildAssociationRef A3Ref = nodeService.getPrimaryParent(testNodeFactory.getMappedNodeRef(A3NodeRef)); + assertEquals("A3 dest is connected to the wrong node", A3Ref.getParentRef(), testNodeFactory.getMappedNodeRef(A2NodeRef)); + ChildAssociationRef A2Ref = nodeService.getPrimaryParent(testNodeFactory.getMappedNodeRef(A2NodeRef)); + assertEquals("A2 dest is connected to the wrong node", A2Ref.getParentRef(), B1NodeRef); + assertEquals("A2 dest owned by wrong repo", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A2NodeRef), TransferModel.PROP_FROM_REPOSITORY_ID), REPO_ID_A); + assertEquals("A3 dest owned by wrong repo", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A3NodeRef), TransferModel.PROP_FROM_REPOSITORY_ID), REPO_ID_A); } finally { endTransaction(); - } - - /** Step 2 - * Chain Sync - * Change Nodes A1 ... A5 source to be received "from repo B" - * Create Node A7 - Fake it to be received "from repo B" - * transfer - */ - String NEW_TITLE="Chain sync"; - - - startNewTransaction(); - try - { - nodeService.setProperty(A1NodeRef, ContentModel.PROP_TITLE, NEW_TITLE); - nodeService.setProperty(A1NodeRef, TransferModel.PROP_ALIEN, Boolean.FALSE); - nodeService.setProperty(A1NodeRef, TransferModel.PROP_FROM_REPOSITORY_ID, REPO_ID_B); - nodeService.setProperty(A1NodeRef, TransferModel.PROP_REPOSITORY_ID, REPO_ID_B); - - nodeService.setProperty(A2NodeRef, ContentModel.PROP_TITLE, NEW_TITLE); - nodeService.setProperty(A2NodeRef, TransferModel.PROP_ALIEN, Boolean.FALSE); - nodeService.setProperty(A2NodeRef, TransferModel.PROP_FROM_REPOSITORY_ID, REPO_ID_B); - nodeService.setProperty(A2NodeRef, TransferModel.PROP_REPOSITORY_ID, REPO_ID_B); - - nodeService.setProperty(A3NodeRef, ContentModel.PROP_TITLE, NEW_TITLE); - nodeService.setProperty(A3NodeRef, TransferModel.PROP_ALIEN, Boolean.FALSE); - nodeService.setProperty(A3NodeRef, TransferModel.PROP_FROM_REPOSITORY_ID, REPO_ID_B); - nodeService.setProperty(A3NodeRef, TransferModel.PROP_REPOSITORY_ID, REPO_ID_B); - - /** - * The repository was mocked to repoistory A. This is repository B - */ - ChildAssociationRef child = nodeService.createNode(A2NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A7"), ContentModel.TYPE_CONTENT); - A7NodeRef = child.getChildRef(); - nodeService.setProperty(A7NodeRef, ContentModel.PROP_TITLE, NEW_TITLE); - nodeService.setProperty(A7NodeRef, ContentModel.PROP_NAME, "A7"); - nodeService.setProperty(A7NodeRef, ContentModel.PROP_TITLE, NEW_TITLE); - nodeService.setProperty(A7NodeRef, TransferModel.PROP_ALIEN, Boolean.FALSE); - nodeService.setProperty(A7NodeRef, TransferModel.PROP_FROM_REPOSITORY_ID, REPO_ID_B); - nodeService.setProperty(A7NodeRef, TransferModel.PROP_REPOSITORY_ID, REPO_ID_B); - - ContentWriter writer = contentService.getWriter(A3NodeRef, ContentModel.PROP_CONTENT, true); - writer.setLocale(CONTENT_LOCALE); - writer.putContent(CONTENT_STRING); } - finally - { - endTransaction(); - } - nodes.add(A7NodeRef); + /** + * Step 2 + * Now transfer in C's nodes + * B2 (Owned by A) gets invaded by C + */ startNewTransaction(); try { + mockedDescriptorService = getMockDescriptorService(REPO_ID_C); + transferServiceImpl.setDescriptorService(mockedDescriptorService); TransferDefinition definition = new TransferDefinition(); + Collection nodes = new ArrayList(); + nodes.add(C1NodeRef); + nodes.add(C2NodeRef); + nodes.add(C3NodeRef); definition.setNodes(nodes); definition.setSync(true); transferService.transfer(targetName, definition); @@ -4866,26 +4836,172 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest endTransaction(); } + startNewTransaction(); try - { - assertTrue("dest node A7 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(A7NodeRef))); + { + assertTrue("dest node A3 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(A3NodeRef))); + assertTrue("dest node C3 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(C3NodeRef))); - assertEquals("dest node A1 Title", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A1NodeRef), ContentModel.PROP_TITLE), NEW_TITLE); - assertEquals("dest node A1 Repository Id", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A1NodeRef), TransferModel.PROP_REPOSITORY_ID), REPO_ID_B); - assertEquals("dest node A1 Repository Id", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A1NodeRef), TransferModel.PROP_FROM_REPOSITORY_ID), repositoryId); - - assertEquals("dest node A2 Title", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A2NodeRef), ContentModel.PROP_TITLE), NEW_TITLE); - assertEquals("dest node A2 Repository Id", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A2NodeRef), TransferModel.PROP_REPOSITORY_ID), REPO_ID_B); - assertEquals("dest node A2 Repository Id", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A2NodeRef), TransferModel.PROP_FROM_REPOSITORY_ID), repositoryId); - - assertEquals("dest node A3 Title", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A3NodeRef), ContentModel.PROP_TITLE), NEW_TITLE); - assertEquals("dest node A3 Repository Id", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A3NodeRef), TransferModel.PROP_REPOSITORY_ID), REPO_ID_B); - assertEquals("dest node A3 Repository Id", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A3NodeRef), TransferModel.PROP_FROM_REPOSITORY_ID), repositoryId); + // Check that A3 dest is a child of A2Dest which is a child of B1 + // Check that C3 dest is a child of A2Dest + ChildAssociationRef A3Ref = nodeService.getPrimaryParent(testNodeFactory.getMappedNodeRef(A3NodeRef)); + assertEquals("A3 dest is connected to the wrong node", A3Ref.getParentRef(), testNodeFactory.getMappedNodeRef(A2NodeRef)); + ChildAssociationRef C3Ref = nodeService.getPrimaryParent(testNodeFactory.getMappedNodeRef(A3NodeRef)); + assertEquals("C3 dest is connected to the wrong node", C3Ref.getParentRef(), testNodeFactory.getMappedNodeRef(A2NodeRef)); + ChildAssociationRef A2Ref = nodeService.getPrimaryParent(testNodeFactory.getMappedNodeRef(A2NodeRef)); + assertEquals("A2 dest is connected to the wrong node", A2Ref.getParentRef(), B1NodeRef); + + assertTrue("A2 dest is not invaded", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(A2NodeRef), TransferModel.ASPECT_ALIEN)); + assertTrue("C3 dest is not invaded", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(C3NodeRef), TransferModel.ASPECT_ALIEN)); + assertFalse("A3 dest is invaded", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(A3NodeRef), TransferModel.ASPECT_ALIEN)); + + assertEquals("A2 dest owned by wrong repo", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A2NodeRef), TransferModel.PROP_FROM_REPOSITORY_ID), REPO_ID_A); + assertEquals("A3 dest owned by wrong repo", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A3NodeRef), TransferModel.PROP_FROM_REPOSITORY_ID), REPO_ID_A); + assertEquals("C3 dest owned by wrong repo", nodeService.getProperty(testNodeFactory.getMappedNodeRef(C3NodeRef), TransferModel.PROP_FROM_REPOSITORY_ID), REPO_ID_C); } finally { endTransaction(); } + + /** + * Step 3 + * Invade A3Dest via transfer of C4 from C + */ + startNewTransaction(); + try + { + mockedDescriptorService = getMockDescriptorService(REPO_ID_C); + transferServiceImpl.setDescriptorService(mockedDescriptorService); + TransferDefinition definition = new TransferDefinition(); + Collection nodes = new ArrayList(); + nodes.add(C4NodeRef); + definition.setNodes(nodes); + definition.setSync(false); + transferService.transfer(targetName, definition); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + assertTrue("dest node A3 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(A3NodeRef))); + assertTrue("dest node C3 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(C3NodeRef))); + assertTrue("dest node C4 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(C4NodeRef))); + + assertTrue("C4 is not an invader", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(C4NodeRef), TransferModel.ASPECT_ALIEN)); + assertTrue("A3 is not an invader", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(A3NodeRef), TransferModel.ASPECT_ALIEN)); + + assertEquals("A2 dest owned by wrong repo", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A2NodeRef), TransferModel.PROP_FROM_REPOSITORY_ID), REPO_ID_A); + assertEquals("A3 dest owned by wrong repo", nodeService.getProperty(testNodeFactory.getMappedNodeRef(A3NodeRef), TransferModel.PROP_FROM_REPOSITORY_ID), REPO_ID_A); + assertEquals("C3 dest owned by wrong repo", nodeService.getProperty(testNodeFactory.getMappedNodeRef(C3NodeRef), TransferModel.PROP_FROM_REPOSITORY_ID), REPO_ID_C); + + } + finally + { + endTransaction(); + } + + /** + * Step 4 + * Uninvade A3 from C by deleting C4 + * Via Sync of A3Dummy (which has the same destination path as A3). + */ + startNewTransaction(); + try + { + nodeService.deleteNode(C4NodeRef); + + } + finally + { + endTransaction(); + } + startNewTransaction(); + try + { + mockedDescriptorService = getMockDescriptorService(REPO_ID_C); + transferServiceImpl.setDescriptorService(mockedDescriptorService); + + TransferDefinition definition = new TransferDefinition(); + Collection nodes = new ArrayList(); + nodes.add(A3Dummy); + definition.setNodes(nodes); + definition.setSync(true); + transferService.transfer(targetName, definition); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + assertTrue("dest node A3 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(A3NodeRef))); + assertTrue("dest node C3 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(C3NodeRef))); + assertFalse("dest node C4 not deleted", nodeService.exists(testNodeFactory.getMappedNodeRef(C4NodeRef))); + + logger.debug("A3 Dest is " + testNodeFactory.getMappedNodeRef(A3NodeRef)); + assertFalse("A3 Dest still invaded by C4", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(A3NodeRef), TransferModel.ASPECT_ALIEN)); + } + finally + { + endTransaction(); + } + + /** + * Step 5 - repeat the above test with transfer(non sync) rather than transfer(sync) + * Uninvade by deleting C3. + */ + startNewTransaction(); + try + { + nodeService.deleteNode(C3NodeRef); + + } + finally + { + endTransaction(); + } + startNewTransaction(); + try + { + mockedDescriptorService = getMockDescriptorService(REPO_ID_C); + transferServiceImpl.setDescriptorService(mockedDescriptorService); + + TransferDefinition definition = new TransferDefinition(); + Collection nodes = new ArrayList(); + + NodeRef C3Deleted = new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, C3NodeRef.getId()); + nodes.add(C3Deleted); + + definition.setNodes(nodes); + definition.setSync(false); + transferService.transfer(targetName, definition); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + assertTrue("dest node A3 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(A3NodeRef))); + assertFalse("dest node C3 not deleted", nodeService.exists(testNodeFactory.getMappedNodeRef(C3NodeRef))); + assertFalse("dest node C4 not deleted", nodeService.exists(testNodeFactory.getMappedNodeRef(C4NodeRef))); + assertFalse("A3 still invaded", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(A3NodeRef), TransferModel.ASPECT_ALIEN)); + assertFalse("A2 still invaded", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(A2NodeRef), TransferModel.ASPECT_ALIEN)); + } + finally + { + endTransaction(); + } + } // test multi repo sync @@ -4909,15 +5025,305 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest return target; } -// /** -// * transfer should only be able to update and delete nodes that are "from" the transferring system -// * -// * not yet implemented. -// */ -// public void testFromRepo() -// { -// assertTrue("not yet implemented", false); -// } + /** + * Test the transfer method behaviour with respect to move and alien nodes. + * + * So we have Repository A transferring content and Repository B is the local repo that we + * move alien nodes in and out. + * + * Tree + *
+     *         B1
+     *    |          |
+     *    C2(p1)    C3(p2)
+     *    |
+     *    A4
+     * 
+ * + * Setup tree above. Validate that A1 is child of C2. + * + * Step 1. Move A4 fron C2 to C3 via transfer. + * C2Dest should stop being invaded C3Dest should be invaded. + */ + public void testMultiRepoTransferMove() throws Exception + { + setDefaultRollback(false); + + String CONTENT_TITLE = "ContentTitle"; + String CONTENT_TITLE_UPDATED = "ContentTitleUpdated"; + Locale CONTENT_LOCALE = Locale.GERMAN; + String CONTENT_STRING = "Hello"; + + String targetName = "testMultiRepoTransferMove"; + TransferTarget transferMe; + NodeRef S0NodeRef; + NodeRef A1NodeRef; + NodeRef B1NodeRef; + NodeRef C1NodeRef; + NodeRef C2NodeRef; + NodeRef C3NodeRef; + NodeRef A4NodeRef; + NodeRef C2DummyNodeRef; + NodeRef C3DummyNodeRef; + QName C2Path = QName.createQName("p2"); + QName C3Path= QName.createQName("p3"); + + startNewTransaction(); + try + { + /** + * Get guest home + */ + String guestHomeQuery = "/app:company_home/app:guest_home"; + ResultSet guestHomeResult = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, SearchService.LANGUAGE_XPATH, guestHomeQuery); + assertEquals("", 1, guestHomeResult.length()); + NodeRef guestHome = guestHomeResult.getNodeRef(0); + + { + /** + * Node Source - located under guest home + */ + String name = GUID.generate(); + ChildAssociationRef child = nodeService.createNode(guestHome, ContentModel.ASSOC_CONTAINS, QName.createQName(name), ContentModel.TYPE_FOLDER); + S0NodeRef = child.getChildRef(); + nodeService.setProperty(S0NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); + nodeService.setProperty(S0NodeRef, ContentModel.PROP_NAME, name); + } + + { + // Node A1 + ChildAssociationRef child = nodeService.createNode(S0NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A1"), ContentModel.TYPE_FOLDER); + A1NodeRef = child.getChildRef(); + nodeService.setProperty(A1NodeRef, ContentModel.PROP_TITLE, "A1"); + nodeService.setProperty(A1NodeRef, ContentModel.PROP_NAME, "A1"); + } + + { + // Node B1 + ChildAssociationRef child = nodeService.createNode(S0NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B1"), ContentModel.TYPE_FOLDER); + B1NodeRef = child.getChildRef(); + nodeService.setProperty(B1NodeRef, ContentModel.PROP_TITLE, "B1"); + nodeService.setProperty(B1NodeRef, ContentModel.PROP_NAME, "B1"); + } + + { + // Node C1 + ChildAssociationRef child = nodeService.createNode(S0NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("C1"), ContentModel.TYPE_FOLDER); + C1NodeRef = child.getChildRef(); + nodeService.setProperty(C1NodeRef, ContentModel.PROP_TITLE, "C1"); + nodeService.setProperty(C1NodeRef, ContentModel.PROP_NAME, "C1"); + } + + { + // Node C2 + ChildAssociationRef child = nodeService.createNode(C1NodeRef, ContentModel.ASSOC_CONTAINS, C2Path, ContentModel.TYPE_FOLDER); + C2NodeRef = child.getChildRef(); + nodeService.setProperty(C2NodeRef, ContentModel.PROP_TITLE, "C2"); + nodeService.setProperty(C2NodeRef, ContentModel.PROP_NAME, "C2"); + } + + { + // Node C3 + ChildAssociationRef child = nodeService.createNode(C1NodeRef, ContentModel.ASSOC_CONTAINS, C3Path, ContentModel.TYPE_FOLDER); + C3NodeRef = child.getChildRef(); + nodeService.setProperty(C3NodeRef, ContentModel.PROP_TITLE, "C3"); + nodeService.setProperty(C3NodeRef, ContentModel.PROP_NAME, "C3"); + } + + { + // Node C2 (Dummy) + ChildAssociationRef child = nodeService.createNode(A1NodeRef, ContentModel.ASSOC_CONTAINS, C2Path, ContentModel.TYPE_FOLDER); + C2DummyNodeRef = child.getChildRef(); + nodeService.setProperty(C2DummyNodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); + nodeService.setProperty(C2DummyNodeRef, ContentModel.PROP_NAME, "C2 Dummy"); + } + + { + // Node C3 (Dummy) + ChildAssociationRef child = nodeService.createNode(A1NodeRef, ContentModel.ASSOC_CONTAINS, C3Path, ContentModel.TYPE_FOLDER); + C3DummyNodeRef = child.getChildRef(); + nodeService.setProperty(C3DummyNodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); + nodeService.setProperty(C3DummyNodeRef, ContentModel.PROP_NAME, "C3 Dummy"); + } + + { + // Node A4 + ChildAssociationRef child = nodeService.createNode(C2DummyNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("C4"), ContentModel.TYPE_FOLDER); + A4NodeRef = child.getChildRef(); + nodeService.setProperty(A4NodeRef, ContentModel.PROP_TITLE, "C4"); + nodeService.setProperty(A4NodeRef, ContentModel.PROP_NAME, "C4"); + } + + // Create the transfer target if it does not already exist + if(!transferService.targetExists(targetName)) + { + transferMe = createTransferTarget(targetName); + } + else + { + transferMe = transferService.getTransferTarget(targetName); + } + } + finally + { + endTransaction(); + } + + /** + * For unit test + * - replace the HTTP transport with the in-process transport + * - Map path from A1 to B1 (So transfer will transfer by path) + * - Map path from C1 to B1 + */ + TransferTransmitter transmitter = new UnitTestInProcessTransmitterImpl(receiver, contentService, transactionService); + transferServiceImpl.setTransmitter(transmitter); + UnitTestTransferManifestNodeFactory testNodeFactory = new UnitTestTransferManifestNodeFactory(this.transferManifestNodeFactory); + transferServiceImpl.setTransferManifestNodeFactory(testNodeFactory); + List> pathMap = testNodeFactory.getPathMap(); + // Map Project A to Project B + // Map Project C to Project B + pathMap.add(new Pair(nodeService.getPath(A1NodeRef), nodeService.getPath(B1NodeRef))); + pathMap.add(new Pair(nodeService.getPath(C1NodeRef), nodeService.getPath(B1NodeRef))); + + DescriptorService mockedDescriptorService = getMockDescriptorService(REPO_ID_C); + transferServiceImpl.setDescriptorService(mockedDescriptorService); + + /** + * Step 1 + * Now transfer in C's nodes to Repo B + */ + startNewTransaction(); + try + { + TransferDefinition definition = new TransferDefinition(); + Collection nodes = new ArrayList(); + nodes.add(C1NodeRef); + nodes.add(C2NodeRef); + nodes.add(C3NodeRef); + definition.setNodes(nodes); + definition.setSync(true); + transferService.transfer(targetName, definition); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + assertTrue("dest node C2 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(C2NodeRef))); + assertTrue("dest node C3 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(C3NodeRef))); + + // Check that C3 dest is a child of B1 + ChildAssociationRef C3Ref = nodeService.getPrimaryParent(testNodeFactory.getMappedNodeRef(C3NodeRef)); + assertEquals("A3 dest is connected to the wrong node", C3Ref.getParentRef(), B1NodeRef); + ChildAssociationRef C2Ref = nodeService.getPrimaryParent(testNodeFactory.getMappedNodeRef(C2NodeRef)); + assertEquals("A2 dest is connected to the wrong node", C2Ref.getParentRef(), B1NodeRef); + } + finally + { + endTransaction(); + } + + mockedDescriptorService = getMockDescriptorService(REPO_ID_A); + transferServiceImpl.setDescriptorService(mockedDescriptorService); + + /** + * Step 2 + * Now transfer in A's nodes + * C2 (Dest) gets invaded by A4 + */ + startNewTransaction(); + try + { + TransferDefinition definition = new TransferDefinition(); + Collection nodes = new ArrayList(); + nodes.add(A4NodeRef); + definition.setNodes(nodes); + definition.setSync(true); + transferService.transfer(targetName, definition); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + assertTrue("dest node A4 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(A4NodeRef))); + assertTrue("dest node C3 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(C3NodeRef))); + assertTrue("dest node C2 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(C2NodeRef))); + // Check that A4 dest is a child of C2Dest which is a child of B1 + ChildAssociationRef A4Ref = nodeService.getPrimaryParent(testNodeFactory.getMappedNodeRef(A4NodeRef)); + assertEquals("A4 dest is connected to the wrong node", A4Ref.getParentRef(), testNodeFactory.getMappedNodeRef(C2NodeRef)); + assertTrue("C2 dest is not invaded", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(C2NodeRef), TransferModel.ASPECT_ALIEN)); + assertFalse("C3 dest is not invaded", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(C3NodeRef), TransferModel.ASPECT_ALIEN)); + } + finally + { + endTransaction(); + } + + /** + * Step 3 + * Now move A3 + * C2 (Dest) gets invaded by A4 + */ + startNewTransaction(); + try + { + nodeService.moveNode(A4NodeRef, C3DummyNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("C4")); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + TransferDefinition definition = new TransferDefinition(); + Collection nodes = new ArrayList(); + nodes.add(A4NodeRef); + definition.setNodes(nodes); + definition.setSync(true); + transferService.transfer(targetName, definition); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + assertTrue("dest node A4 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(A4NodeRef))); + assertTrue("dest node C3 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(C3NodeRef))); + assertTrue("dest node C2 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(C2NodeRef))); + + // Check that A4 dest is a child of C3Dest which is a child of B1 + ChildAssociationRef A4Ref = nodeService.getPrimaryParent(testNodeFactory.getMappedNodeRef(A4NodeRef)); + assertEquals("A4 dest is connected to the wrong node", A4Ref.getParentRef(), testNodeFactory.getMappedNodeRef(C3NodeRef)); + assertTrue("A4 dest is not invaded", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(A4NodeRef), TransferModel.ASPECT_ALIEN)); + assertTrue("C3 dest is not invaded", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(C3NodeRef), TransferModel.ASPECT_ALIEN)); + assertFalse("C2 dest is still invaded", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(C2NodeRef), TransferModel.ASPECT_ALIEN)); + } + finally + { + endTransaction(); + } + + } + + /** + * transfer should only be able to update and delete nodes that are "from" the transferring system + */ + public void testFromRepo() + { + assertTrue("not yet implemented", false); + } private void createUser(String userName, String password) {