diff --git a/config/alfresco/transfer-service-context.xml b/config/alfresco/transfer-service-context.xml index 4b06a4495a..5dc93022c4 100644 --- a/config/alfresco/transfer-service-context.xml +++ b/config/alfresco/transfer-service-context.xml @@ -57,8 +57,9 @@ - + + + * So any children that are only invaded by the specified repository are deleted. + *

+ * Folders which are invaded by more than one repository will remain. + * * @param parentNodeRef the root to prune * @param fromRepositoryId the repositoryId to prune. */ @@ -29,25 +34,38 @@ public interface AlienProcessor */ public boolean isAlien(NodeRef nodeRef); - /** - * Called before deleting an alien node. - * - * @param nodeBeingDeleted node about to be deleted - */ - public void beforeDeleteAlien(NodeRef deletedNodeRef); - /** * Called before creating a child of a transferred node. - * + *

* When a new node is created as a child of a Transferred or Alien node then * the new node needs to be marked as an alien. *

* Then the tree needs to be walked upwards to mark all parent - * transferred nodes as alien. + * transferred nodes as alien. * * @param childAssocRef the association ref to the new node * @param repositoryId - the repositoryId of the system who owns the new node. + * @param isNewNode - is this a new nide */ - public void onCreateChild(ChildAssociationRef childAssocRef, String repositoryId); - + public void onCreateChild(ChildAssociationRef childAssocRef, String repositoryId, boolean isNewNode); + + /** + * Called when an alien node has been moved from one parent to another. + *

+ * If the new parent is transferred or alien may make the new parent an alien. + *

+ * The alien node may also stop being an alien node. + */ + public void afterMoveAlien(ChildAssociationRef newAssocRef); + + /** + * Called before deleting an alien node. + *

+ * The tree needs to be walked upwards to take account of the removed alien node. + * + * @param nodeBeingDeleted node about to be deleted + * @param oldRef null if the deleted node is still "in place" and readable else the old ref prior to + * the node being moved. + */ + public void beforeDeleteAlien(NodeRef deletedNodeRef, ChildAssociationRef oldRef); } diff --git a/source/java/org/alfresco/repo/transfer/AlienProcessorImpl.java b/source/java/org/alfresco/repo/transfer/AlienProcessorImpl.java index 758d1a1cd0..77d6885437 100644 --- a/source/java/org/alfresco/repo/transfer/AlienProcessorImpl.java +++ b/source/java/org/alfresco/repo/transfer/AlienProcessorImpl.java @@ -19,6 +19,7 @@ import org.alfresco.service.cmr.dictionary.DictionaryService; 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.descriptor.DescriptorService; import org.alfresco.service.namespace.QName; import org.alfresco.util.PropertyCheck; import org.apache.commons.logging.Log; @@ -32,6 +33,7 @@ public class AlienProcessorImpl implements AlienProcessor private NodeService nodeService; private BehaviourFilter behaviourFilter; private DictionaryService dictionaryService; + private DescriptorService descriptorService; private static final Log log = LogFactory.getLog(AlienProcessorImpl.class); @@ -40,21 +42,26 @@ public class AlienProcessorImpl implements AlienProcessor PropertyCheck.mandatory(this, "nodeService", nodeService); PropertyCheck.mandatory(this, "behaviourFilter", behaviourFilter); PropertyCheck.mandatory(this, "dictionaryService", getDictionaryService()); + PropertyCheck.mandatory(this, "descriptorService", descriptorService); } - public void onCreateChild(ChildAssociationRef childAssocRef, final String repositoryId) + public void onCreateChild(ChildAssociationRef childAssocRef, final String repositoryId, boolean isNewNode) { log.debug("on create child association to transferred node"); ChildAssociationRef currentAssoc = childAssocRef; - + NodeRef parentNodeRef = currentAssoc.getParentRef(); + NodeRef childNodeRef = currentAssoc.getChildRef(); + if(!childAssocRef.isPrimary()) { log.debug("not a primary assoc - do nothing"); return; } - - // TODO Needs to check assoc is a cm:contains or subtype of cm:contains + + /** + * check assoc is a cm:contains or subtype of cm:contains + */ if(!childAssocRef.getTypeQName().equals(ContentModel.ASSOC_CONTAINS)) { Collection subAspects = dictionaryService.getSubAspects(ContentModel.ASSOC_CONTAINS, true); @@ -64,14 +71,11 @@ public class AlienProcessorImpl implements AlienProcessor return; } } - - NodeRef parentNodeRef = currentAssoc.getParentRef(); - NodeRef childNodeRef = currentAssoc.getChildRef(); - if(!nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED)) + if(!(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED) || nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_ALIEN))) { - log.debug("parent was not transferred - do nothing"); - return; + log.debug("parent was not transferred or alien - do nothing"); + return; } if(!nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_ALIEN)) @@ -83,8 +87,8 @@ public class AlienProcessorImpl implements AlienProcessor { log.debug("parent was not alien and this node is from the same repo - do nothing"); return; - } - } + } + } } /** @@ -143,30 +147,64 @@ public class AlienProcessorImpl implements AlienProcessor log.debug("parent is not a transferred node"); currentAssoc = null; } - } - } - - public void beforeDeleteAlien(NodeRef deletedNodeRef) + } + } + + public void beforeDeleteAlien(NodeRef deletedNodeRef, ChildAssociationRef oldAssoc) { log.debug("before delete node - need to check for alien invaders"); - Liststuff = (List)nodeService.getProperty(deletedNodeRef, TransferModel.PROP_INVADED_BY); - + Liststuff = (List)nodeService.getProperty(deletedNodeRef, TransferModel.PROP_INVADED_BY); Vector exInvaders = new Vector(stuff); - ChildAssociationRef currentAssoc = nodeService.getPrimaryParent(deletedNodeRef); + /** + * some fudge to get this to run after the node has been moved. + */ + ChildAssociationRef currentAssoc; + if(oldAssoc != null) + { + currentAssoc = oldAssoc; + } + else + { + currentAssoc = nodeService.getPrimaryParent(deletedNodeRef); + } while(currentAssoc != null && exInvaders != null && exInvaders.size() > 0) { NodeRef parentNodeRef = currentAssoc.getParentRef(); - NodeRef currentNodeRef = currentAssoc.getChildRef(); + NodeRef currentNodeRef; + + if(currentAssoc == oldAssoc) + { + currentNodeRef = deletedNodeRef; + } + else + { + currentNodeRef = currentAssoc.getChildRef(); + } /** * Does the parent have alien invaders ? */ if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_ALIEN)) { - log.debug("parent node is alien - check siblings"); + log.debug("parent node is invaded by aliens"); + + /** + * Remove the parent's origin from the list of exInvaders since the parent also invades. + */ + String parentRepoId; + if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED)) + { + parentRepoId = (String)nodeService.getProperty(parentNodeRef, TransferModel.PROP_FROM_REPOSITORY_ID); + } + else + { + parentRepoId = descriptorService.getCurrentRepositoryDescriptor().getId(); + } + + exInvaders.remove(parentRepoId); /** * For each invader of the deletedNode @@ -178,8 +216,8 @@ public class AlienProcessorImpl implements AlienProcessor log.debug("Checking exInvader:" + exInvader); /** - * Check the siblings of this node to see whether there are any other alien nodes for this invader. - */ + * 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); @@ -190,7 +228,7 @@ public class AlienProcessorImpl implements AlienProcessor if(childRef.equals(currentNodeRef)) { - // do nothing - this is the node we are working with. + // do nothing - this is the node we are working with. } else { @@ -266,7 +304,223 @@ public class AlienProcessorImpl implements AlienProcessor } } // end of while } - + + + public void afterMoveAlien(ChildAssociationRef newAssocRef) + { + log.debug("after move alien: newAssocRef"); + + NodeRef parentNodeRef = newAssocRef.getParentRef(); + NodeRef childNodeRef = newAssocRef.getChildRef(); + + List childInvadedBy = (List)nodeService.getProperty(childNodeRef, TransferModel.PROP_INVADED_BY); + + if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED) || nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_ALIEN)) + { + ListaliensToAdd = new ArrayList(); + + log.debug("new parent is transferred or alien"); + + /** + * check assoc is a cm:contains or subtype of cm:contains + */ + if(!newAssocRef.getTypeQName().equals(ContentModel.ASSOC_CONTAINS)) + { + Collection subAspects = dictionaryService.getSubAspects(ContentModel.ASSOC_CONTAINS, true); + if(!subAspects.contains(newAssocRef.getTypeQName())) + { + log.debug("not a subtype of cm:contains - may need to uninvade"); + + String parentRepoId = descriptorService.getCurrentRepositoryDescriptor().getId(); + retreatDownwards(childNodeRef, parentRepoId); + + return; + } + } + + if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_ALIEN)) + { + // parent is already alien + ListparentInvadedBy = (List)nodeService.getProperty(parentNodeRef, TransferModel.PROP_INVADED_BY); + for(String invader : childInvadedBy) + { + if(!parentInvadedBy.contains(invader)) + { + aliensToAdd.add(invader); + } + } + } + else + { + // parent is transfered but does not yet contain aliens + String parentFromRepo = (String)nodeService.getProperty(parentNodeRef, TransferModel.PROP_FROM_REPOSITORY_ID); + { + for(String invader : childInvadedBy) + { + if(invader.equalsIgnoreCase(parentFromRepo)) + { + // The invader is the same repo + log.debug("child node is from the same repo as a non invaded node"); + retreatDownwards(childNodeRef, parentFromRepo); + } + else + { + aliensToAdd.add(invader); + } + } + } + } + + /** + * Now deal with the parents of this alien node + */ + ChildAssociationRef currentAssoc = newAssocRef; + while(currentAssoc != null && aliensToAdd.size() > 0) + { + parentNodeRef = currentAssoc.getParentRef(); + childNodeRef = currentAssoc.getChildRef(); + + if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED) || nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_ALIEN)) + { + for(String alienRepoId : aliensToAdd) + { + if (!isInvaded(parentNodeRef, alienRepoId)) + { + if(log.isDebugEnabled()) + { + log.debug("alien invades parent node:" + parentNodeRef + ", repositoryId:" + alienRepoId); + } + + final NodeRef newAlien = parentNodeRef; + final String fAlien = alienRepoId; + /** + * 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 + { + getBehaviourFilter().disableBehaviour(newAlien, ContentModel.ASPECT_AUDITABLE); + getBehaviourFilter().disableBehaviour(newAlien, ContentModel.ASPECT_LOCKABLE); + setAlien(newAlien, fAlien); + return null; + } + }; + AuthenticationUtil.runAs(actionRunAs, AuthenticationUtil.getSystemUserName()); + } + else + { + log.debug("parent node is already invaded by:" + alienRepoId); + aliensToAdd.remove(alienRepoId); + } + + // Yes the parent has been invaded so step up to the parent's parent + currentAssoc = nodeService.getPrimaryParent(parentNodeRef); + } + } + else + { + log.debug("parent is not a transferred node"); + currentAssoc = null; + } + } + } + else + { + log.debug("parent was not transferred or alien"); + + // TODO Need to remove the alien flags + String parentRepoId = descriptorService.getCurrentRepositoryDescriptor().getId(); + retreatDownwards(childNodeRef, parentRepoId); + + return; + } + } // after move alien + + /** + * Top down un-invasion + *

+ * Steps down the tree retreating from all the invaded nodes. + *

+ * The retreat will stop is there is a "sub-invasion". + *

+ * @param nodeRef the top of the tree + * @param repoId the repository that is retreating. + */ + private void retreatDownwards(NodeRef nodeRef, String fromRepositoryId) + { + Stack nodesToRetreat = new Stack(); + nodesToRetreat.add(nodeRef); + + /** + * Now go and do the retreat. + */ + while(!nodesToRetreat.isEmpty()) + { + if(log.isDebugEnabled()) + { + log.debug("retreat :" + nodeRef + ", repoId:" + fromRepositoryId); + } + + /** + * for the current node and all alien children + * + * if they are "from" the retreating repository then + */ + NodeRef currentNodeRef = nodesToRetreat.pop(); + + log.debug("retreatNode:" + currentNodeRef); + + if(getNodeService().hasAspect(currentNodeRef, TransferModel.ASPECT_ALIEN)) + { + // Yes this is an alien node + ListinvadedBy = (List)getNodeService().getProperty(currentNodeRef, TransferModel.PROP_INVADED_BY); + + String parentRepoId; + if(nodeService.hasAspect(currentNodeRef, TransferModel.ASPECT_TRANSFERRED)) + { + log.debug("node is transferred"); + parentRepoId = (String)nodeService.getProperty(currentNodeRef, TransferModel.PROP_FROM_REPOSITORY_ID); + } + else + { + log.debug("node is local"); + parentRepoId = descriptorService.getCurrentRepositoryDescriptor().getId(); + } + + if(fromRepositoryId.equalsIgnoreCase(parentRepoId)) + { + // This node is "owned" by the retreating repo + // Yes we are invaded by fromRepositoryId + if(invadedBy.size() == 1) + { + // we are invaded by a single repository which must be fromRepositoryId + log.debug("no longe alien:" + currentNodeRef); + getNodeService().removeAspect(currentNodeRef, TransferModel.ASPECT_ALIEN); + } + else + { + invadedBy.remove(parentRepoId); + getNodeService().setProperty(currentNodeRef, TransferModel.PROP_INVADED_BY, (Serializable)invadedBy); + } + + //TODO replace with a more efficient query + List refs = getNodeService().getChildAssocs(currentNodeRef); + for(ChildAssociationRef ref : refs) + { + if(log.isDebugEnabled()) + { + log.debug("will need to check child:" + ref); + } + nodesToRetreat.push(ref.getChildRef()); + } + } + } + } + } // retreatDownwards + public boolean isAlien(NodeRef nodeRef) { return nodeService.hasAspect(nodeRef, TransferModel.ASPECT_ALIEN); @@ -479,7 +733,7 @@ public class AlienProcessorImpl implements AlienProcessor } /** - * Recalculate the whether this node is invaded by the specified repository + * Determine whether the specified node is invaded by the specified repository * @param folderNodeRef the node to re-calculate * @param fromRepositoryId the repository who is transferring. * @@ -527,7 +781,7 @@ public class AlienProcessorImpl implements AlienProcessor return stillInvaded; } - + public void setNodeService(NodeService nodeService) { this.nodeService = nodeService; @@ -557,4 +811,14 @@ public class AlienProcessorImpl implements AlienProcessor { return dictionaryService; } + + public void setDescriptorService(DescriptorService descriptorService) + { + this.descriptorService = descriptorService; + } + + public DescriptorService getDescriptorService() + { + return descriptorService; + } } diff --git a/source/java/org/alfresco/repo/transfer/RepoPrimaryManifestProcessorImpl.java b/source/java/org/alfresco/repo/transfer/RepoPrimaryManifestProcessorImpl.java index a6c97f7391..ad508e017f 100644 --- a/source/java/org/alfresco/repo/transfer/RepoPrimaryManifestProcessorImpl.java +++ b/source/java/org/alfresco/repo/transfer/RepoPrimaryManifestProcessorImpl.java @@ -338,7 +338,7 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB */ if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED)) { - alienProcessor.onCreateChild(newNode, header.getRepositoryId()); + alienProcessor.onCreateChild(newNode, header.getRepositoryId(), true); } // Is the node that we've just added the parent of any orphans that @@ -408,7 +408,7 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB */ if(nodeService.hasAspect(newRef.getParentRef(), TransferModel.ASPECT_TRANSFERRED)) { - alienProcessor.onCreateChild(newRef, header.getRepositoryId()); + alienProcessor.onCreateChild(newRef, header.getRepositoryId(), true); } } // We can now remove the record of these orphans, as their parent @@ -477,19 +477,16 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB */ if(nodeService.hasAspect(currentParent.getParentRef(), TransferModel.ASPECT_ALIEN)) { - // old parent node ref may be alien - alienProcessor.beforeDeleteAlien(node.getNodeRef()); + // old parent node ref may be alien so treat as a delete + alienProcessor.beforeDeleteAlien(currentParent.getChildRef(), null); } // Yes, we need to move the node ChildAssociationRef newNode = nodeService.moveNode(nodeToUpdate, parentNodeRef, parentAssocType, parentAssocName); logProgress("Moved node " + nodeToUpdate + " to be under parent node " + parentNodeRef); - // We may have created a new alien. - if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED)) - { - alienProcessor.onCreateChild(newNode, header.getRepositoryId()); - } + alienProcessor.afterMoveAlien(newNode); + } log.info("Resolved parent node to " + parentNodeRef); diff --git a/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImpl.java b/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImpl.java index c8e973fe53..308a94fb5c 100644 --- a/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImpl.java +++ b/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImpl.java @@ -41,7 +41,9 @@ import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.alfresco.model.ContentModel; +import org.alfresco.repo.copy.CopyServicePolicies.BeforeCopyPolicy; import org.alfresco.repo.node.NodeServicePolicies; +import org.alfresco.repo.node.NodeServicePolicies.OnMoveNodePolicy; import org.alfresco.repo.policy.BehaviourFilter; import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.policy.PolicyComponent; @@ -86,7 +88,9 @@ import org.springframework.util.FileCopyUtils; */ public class RepoTransferReceiverImpl implements TransferReceiver, NodeServicePolicies.OnCreateChildAssociationPolicy, - NodeServicePolicies.BeforeDeleteNodePolicy + NodeServicePolicies.BeforeDeleteNodePolicy, + NodeServicePolicies.OnRestoreNodePolicy, + NodeServicePolicies.OnMoveNodePolicy { /** @@ -195,14 +199,38 @@ public class RepoTransferReceiverImpl implements TransferReceiver, TransferModel.ASPECT_TRANSFERRED, new JavaBehaviour(this, "onCreateChildAssociation", NotificationFrequency.EVERY_EVENT)); + /** + * For every new child of a node with the trx:alien aspect run this.onCreateChildAssociation + */ + this.getPolicyComponent().bindAssociationBehaviour( + NodeServicePolicies.OnCreateChildAssociationPolicy.QNAME, + TransferModel.ASPECT_ALIEN, + new JavaBehaviour(this, "onCreateChildAssociation", NotificationFrequency.EVERY_EVENT)); + /** * For every node with the trx:alien aspect run this.beforeDeleteNode */ this.getPolicyComponent().bindClassBehaviour( NodeServicePolicies.BeforeDeleteNodePolicy.QNAME, TransferModel.ASPECT_ALIEN, - new JavaBehaviour(this, "beforeDeleteNode", NotificationFrequency.EVERY_EVENT)); - + new JavaBehaviour(this, "beforeDeleteNode", NotificationFrequency.EVERY_EVENT)); + + /** + * For every restore of a node with the trx:alien aspect + */ + this.getPolicyComponent().bindClassBehaviour( + NodeServicePolicies.OnRestoreNodePolicy.QNAME, + TransferModel.ASPECT_ALIEN, + new JavaBehaviour(this, "onRestoreNode", NotificationFrequency.EVERY_EVENT)); + + /** + * For every move of a node with the trx:alien aspect. + */ + this.getPolicyComponent().bindClassBehaviour( + NodeServicePolicies.OnMoveNodePolicy.QNAME, + TransferModel.ASPECT_ALIEN, + new JavaBehaviour(this, "onMoveNode", NotificationFrequency.EVERY_EVENT)); + } /* @@ -968,7 +996,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); + alienProcessor.onCreateChild(childAssocRef, localRepositoryId, isNewNode); } /** @@ -979,7 +1007,36 @@ public class RepoTransferReceiverImpl implements TransferReceiver, public void beforeDeleteNode(NodeRef deletedNodeRef) { log.debug("on delete node - need to check for transferred node"); - alienProcessor.beforeDeleteAlien(deletedNodeRef); + alienProcessor.beforeDeleteAlien(deletedNodeRef, null); + } + + /** + * When a transferred node is restored it may be a new invader or it may no + * longer be an invader. + *

+ * Walk the tree checking the invasion status! + */ + public void onRestoreNode(ChildAssociationRef childAssocRef) + { + log.debug("on restore node"); + final String localRepositoryId = descriptorService.getCurrentRepositoryDescriptor().getId(); + log.debug("restoredAssocRef:" + childAssocRef); + alienProcessor.afterMoveAlien(childAssocRef); + } + + /** + * When an alien node is moved it may un-invade its old location and invade a new + * location. The node may also cease to be alien. + */ + public void onMoveNode(ChildAssociationRef oldChildAssocRef, + ChildAssociationRef newChildAssocRef) + { + + log.debug("onMoveNode"); + log.debug("oldChildAssocRef:" + oldChildAssocRef); + log.debug("newChildAssocRef:" + newChildAssocRef); + alienProcessor.beforeDeleteAlien(newChildAssocRef.getChildRef(), oldChildAssocRef); + alienProcessor.afterMoveAlien(newChildAssocRef); } public void setDescriptorService(DescriptorService descriptorService) diff --git a/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java b/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java index 605e8fc839..c7fa714ddb 100644 --- a/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java +++ b/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java @@ -2789,11 +2789,13 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest * * A1 * | | | - * A2 A3 (Content Node) B9 Alien Content Node + * A2 A3 (Content Node) B9 (Alien Content Node) * | * A4 A5 B10 (Alien Content Node) A6 * | | - * A7 B11 (Alien Content Node) A8 B12 B13 Alien Contact Nodes + * A7 B11 (Alien Content Node) A8 B12 B13 (Alien Content Node) + * | + * B14 * * Test steps - *

    @@ -2801,9 +2803,11 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest * transfer(sync) *
  1. add Alien node B9. A1 becomes Alien.
  2. *
  3. remove alien node B9. A1 becomes non Alien.
  4. +
  5. restore alien node B9. A1 becomes non Alien again.
  6. *
  7. add Alien node B10. A1 and A2 become Alien
  8. *
  9. remove Alien node B10. A1 and A2 become non Alien
  10. - *
  11. add B12 A6, A2, A1 becomes Alien
  12. + *
  13. add B12 and B14 A6, A2, A1 becomes Alien
  14. + *
  15. remove B14, B12, A6, A2, A1 remain Alien
  16. *
  17. add B13 A6, A2, A1 remains Alien
  18. *
  19. remove B13 A6, A2, A1 remains Alien
  20. *
  21. remove B12 A6, A2, A1 becomes non Alien.
  22. @@ -2813,11 +2817,6 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest * transfer sync * (A5, A6, A7 and A8 should be deleted A2 and A4 remain since they contain alien content.) *
- * - * TODO test move and alien - * - * TODO test restore and alien - * */ public void testTransferInvadedByLocalAlienNodes() throws Exception { @@ -2867,6 +2866,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest NodeRef B11NodeRef; NodeRef B12NodeRef; NodeRef B13NodeRef; + NodeRef B14NodeRef; NodeRef destNodeRef; @@ -3091,11 +3091,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest { NodeRef A1destNodeRef = testNodeFactory.getMappedNodeRef(A1NodeRef); NodeRef A3destNodeRef = testNodeFactory.getMappedNodeRef(A3NodeRef); - - // Temp code List invaders = (List) nodeService.getProperty(A1destNodeRef, TransferModel.PROP_INVADED_BY); - logger.debug("MER WOZ ERE AFTER B9 deleted" + invaders); - assertTrue("dest node ref does not exist", nodeService.exists(A1destNodeRef)); assertFalse("node A1 is still alien", (Boolean)nodeService.hasAspect(A1destNodeRef, TransferModel.ASPECT_ALIEN)); assertFalse("node A3 is alien", (Boolean)nodeService.hasAspect(A3destNodeRef, TransferModel.ASPECT_ALIEN)); @@ -3176,20 +3172,21 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest /** * Step 6 - * add B12 (child of A6) A6, A2, A1 becomes Alien + * add B12 (child of A6) and B14 A6, A2, A1 becomes Alien */ startNewTransaction(); try { destNodeRef = testNodeFactory.getMappedNodeRef(A6NodeRef); - ChildAssociationRef child = nodeService.createNode(destNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B12"), ContentModel.TYPE_CONTENT); + ChildAssociationRef child = nodeService.createNode(destNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B12"), ContentModel.TYPE_FOLDER); B12NodeRef = child.getChildRef(); nodeService.setProperty(B12NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); - nodeService.setProperty(B12NodeRef, ContentModel.PROP_NAME, "B12"); - - ContentWriter writer = contentService.getWriter(B12NodeRef, ContentModel.PROP_CONTENT, true); - writer.setLocale(CONTENT_LOCALE); - writer.putContent(CONTENT_STRING); + nodeService.setProperty(B12NodeRef, ContentModel.PROP_NAME, "B12"); + + child = nodeService.createNode(B12NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B14"), ContentModel.TYPE_CONTENT); + B14NodeRef = child.getChildRef(); + nodeService.setProperty(B14NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); + nodeService.setProperty(B14NodeRef, ContentModel.PROP_NAME, "B14"); } finally { @@ -3207,6 +3204,41 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest assertTrue("node A1 is not alien", (Boolean)nodeService.hasAspect(A1destNodeRef, TransferModel.ASPECT_ALIEN)); assertTrue("node A2 is not alien", (Boolean)nodeService.hasAspect(A2destNodeRef, TransferModel.ASPECT_ALIEN)); assertTrue("node A6 is not alien", (Boolean)nodeService.hasAspect(A6destNodeRef, TransferModel.ASPECT_ALIEN)); + assertTrue("node B14 is not alien", (Boolean)nodeService.hasAspect(B14NodeRef, TransferModel.ASPECT_ALIEN)); + assertTrue("node B12 is not alien", (Boolean)nodeService.hasAspect(B12NodeRef, TransferModel.ASPECT_ALIEN)); + } + + finally + { + endTransaction(); + } + + /** + * Step 6a. + * Delete B14. B12 remains alien + */ + startNewTransaction(); + try + { + nodeService.deleteNode(B14NodeRef); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + // Now validate that the target node exists and has similar properties to the source + NodeRef A1destNodeRef = testNodeFactory.getMappedNodeRef(A1NodeRef); + NodeRef A2destNodeRef = testNodeFactory.getMappedNodeRef(A2NodeRef); + NodeRef A6destNodeRef = testNodeFactory.getMappedNodeRef(A6NodeRef); + + assertTrue("node A1 is not alien", (Boolean)nodeService.hasAspect(A1destNodeRef, TransferModel.ASPECT_ALIEN)); + assertTrue("node A2 is not alien", (Boolean)nodeService.hasAspect(A2destNodeRef, TransferModel.ASPECT_ALIEN)); + assertTrue("node A6 is not alien", (Boolean)nodeService.hasAspect(A6destNodeRef, TransferModel.ASPECT_ALIEN)); + assertTrue("node B12 is not alien", (Boolean)nodeService.hasAspect(B12NodeRef, TransferModel.ASPECT_ALIEN)); } finally @@ -3491,6 +3523,341 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest } } + /** + * Test restore of a local node. + *
+     * Tree of nodes
+     *     A1   B1
+     *     |
+     *     B2
+     *     |
+     *     B3
+     * 
+     * 
    + *
  1. Add B2. A1 is alien.
  2. + *
  3. Delete B2. A1 not alien
  4. + *
  5. Restore B2. A1 is alien
  6. + *
  7. Add B3. A1 is alien
  8. + *
  9. Delete B2. A1 not alien
  10. + *
  11. Restore to B1. B2 and B3 not alien.
  12. + *
+ * @throws Exception + */ + public void testLocalAlienRestore() throws Exception + { + setDefaultRollback(false); + + String CONTENT_TITLE = "ContentTitle"; + String CONTENT_TITLE_UPDATED = "ContentTitleUpdated"; + Locale CONTENT_LOCALE = Locale.JAPAN; + String CONTENT_STRING = "Hello"; + + + /** + * Now go ahead and create our first transfer target + */ + String targetName = "testRestoreOfAlienNodes"; + TransferTarget transferMe; + + NodeRef S0NodeRef; + NodeRef A0NodeRef; + NodeRef A1NodeRef; + NodeRef B1NodeRef; + NodeRef B2NodeRef; + NodeRef B3NodeRef; + + NodeRef destNodeRef; + + 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); + + /** + * Create a test nodes A1 through A8 that we will read and write + */ + { + // Node S0 + 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("A0"), ContentModel.TYPE_FOLDER); + A0NodeRef = child.getChildRef(); + nodeService.setProperty(A0NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); + nodeService.setProperty(A0NodeRef, ContentModel.PROP_NAME, "A0"); + } + { + // Node A1 + ChildAssociationRef child = nodeService.createNode(A0NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A1"), ContentModel.TYPE_FOLDER); + A1NodeRef = child.getChildRef(); + nodeService.setProperty(A1NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); + 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, CONTENT_TITLE); + nodeService.setProperty(B1NodeRef, ContentModel.PROP_NAME, "B1"); + } + + // 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 + * - replace the node factory with one that will map node refs, paths etc. + * + * Mock the transfer service to be from Repo A + */ + TransferTransmitter transmitter = new UnitTestInProcessTransmitterImpl(receiver, contentService, transactionService); + transferServiceImpl.setTransmitter(transmitter); + UnitTestTransferManifestNodeFactory testNodeFactory = new UnitTestTransferManifestNodeFactory(this.transferManifestNodeFactory); + transferServiceImpl.setTransferManifestNodeFactory(testNodeFactory); + List> pathMap = testNodeFactory.getPathMap(); + pathMap.add(new Pair(nodeService.getPath(A0NodeRef), nodeService.getPath(B1NodeRef))); + DescriptorService mockedDescriptorService = getMockDescriptorService(REPO_ID_A); + transferServiceImpl.setDescriptorService(mockedDescriptorService); + + /** + * Step 1. add A1 + * transfer(sync) + */ + startNewTransaction(); + try + { + /** + * Transfer Nodes A1 + */ + { + TransferDefinition definition = new TransferDefinition(); + Setnodes = new HashSet(); + nodes.add(A1NodeRef); + definition.setNodes(nodes); + definition.setSync(true); + transferService.transfer(targetName, definition); + } + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + // Now validate that the target node exists and has similar properties to the source + NodeRef A1destNodeRef = testNodeFactory.getMappedNodeRef(A1NodeRef); + assertTrue("dest node ref does not exist", nodeService.exists(A1destNodeRef)); + assertFalse("A1 is alien", nodeService.hasAspect(A1destNodeRef, TransferModel.ASPECT_ALIEN)); + // Check injected transferred aspect. + assertNotNull("transferredAspect", (String)nodeService.getProperty(A1destNodeRef, TransferModel.PROP_REPOSITORY_ID)); + } + finally + { + endTransaction(); + } + + /** + * Step 2 add Alien node B1 child of A1(dest). + */ + startNewTransaction(); + try + { + destNodeRef = testNodeFactory.getMappedNodeRef(A1NodeRef); + ChildAssociationRef child = nodeService.createNode(destNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B2"), ContentModel.TYPE_FOLDER); + B2NodeRef = child.getChildRef(); + nodeService.setProperty(B2NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); + nodeService.setProperty(B2NodeRef, ContentModel.PROP_NAME, "B2"); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + // Now validate that the target node exists and has similar properties to the source + NodeRef A1destNodeRef = testNodeFactory.getMappedNodeRef(A1NodeRef); + + assertTrue("dest node ref does not exist", nodeService.exists(A1destNodeRef)); + // Check injected transferred aspect. + 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)); + assertTrue("node B2 is not alien", (Boolean)nodeService.hasAspect(B2NodeRef, TransferModel.ASPECT_ALIEN)); + } + finally + { + endTransaction(); + } + + /** + * Step 3 remove alien node B2. A1 becomes non Alien. + */ + startNewTransaction(); + try + { + logger.debug("delete node B2"); + nodeService.deleteNode(B2NodeRef); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + NodeRef A1destNodeRef = testNodeFactory.getMappedNodeRef(A1NodeRef); + List invaders = (List) nodeService.getProperty(A1destNodeRef, TransferModel.PROP_INVADED_BY); + assertTrue("dest node ref does not exist", nodeService.exists(A1destNodeRef)); + assertFalse("node A1 is still alien", (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)); + } + finally + { + endTransaction(); + } + + /** + * Step 4 restore alien node B2. A1 becomes Alien again + */ + startNewTransaction(); + try + { + logger.debug("restore node B2"); + NodeRef B2ArchiveNodeRef = new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, B2NodeRef.getId()); + nodeService.restoreNode(B2ArchiveNodeRef, testNodeFactory.getMappedNodeRef(A1NodeRef), ContentModel.ASSOC_CONTAINS, QName.createQName("B2")); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + NodeRef A1destNodeRef = testNodeFactory.getMappedNodeRef(A1NodeRef); + assertTrue("dest node ref does not exist", nodeService.exists(A1destNodeRef)); + assertTrue("node A1 is not alien", (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)); + } + finally + { + endTransaction(); + } + + /** + * Step 5 - add B3 + */ + startNewTransaction(); + try + { + ChildAssociationRef child = nodeService.createNode(B2NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B3"), ContentModel.TYPE_FOLDER); + B3NodeRef = child.getChildRef(); + nodeService.setProperty(B3NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE); + nodeService.setProperty(B3NodeRef, ContentModel.PROP_NAME, "B3"); + } + finally + { + endTransaction(); + } + startNewTransaction(); + try + { + assertTrue("node B3 is not alien", (Boolean)nodeService.hasAspect(B3NodeRef, TransferModel.ASPECT_ALIEN)); + } + finally + { + endTransaction(); + } + + /** + * Step 5 remove alien node B2. A1 becomes non Alien (again). + */ + startNewTransaction(); + try + { + logger.debug("delete node B2"); + nodeService.deleteNode(B2NodeRef); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + NodeRef A1destNodeRef = testNodeFactory.getMappedNodeRef(A1NodeRef); + List invaders = (List) nodeService.getProperty(A1destNodeRef, TransferModel.PROP_INVADED_BY); + assertTrue("dest node ref does not exist", nodeService.exists(A1destNodeRef)); + assertFalse("node A1 is still alien", (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)); + } + finally + { + endTransaction(); + } + + /** + * Step6 restore B2 and B3 to B1. + */ + startNewTransaction(); + try + { + logger.debug("restore node B2"); + NodeRef B2ArchiveNodeRef = new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, B2NodeRef.getId()); + nodeService.restoreNode(B2ArchiveNodeRef, B1NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B2")); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + assertFalse("node A1 is still alien", (Boolean)nodeService.hasAspect(testNodeFactory.getMappedNodeRef(A1NodeRef), TransferModel.ASPECT_ALIEN)); + assertFalse("node A2 is still alien", (Boolean)nodeService.hasAspect(B2NodeRef, TransferModel.ASPECT_ALIEN)); + assertFalse("node A3 is still alien", (Boolean)nodeService.hasAspect(B3NodeRef, TransferModel.ASPECT_ALIEN)); + } + finally + { + endTransaction(); + } + } + + /** * Test the transfer method with regard to permissions on a node. @@ -5034,16 +5401,31 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest * Tree *
      *         B1
-     *    |          |
-     *    C2(p1)    C3(p2)
+     *    |          |         |
+     *    C2(p1)    C3(p2)     A4
+     *    |          
+     *    A5        
      *    |
-     *    A4
+     *    B6
      * 
* - * Setup tree above. Validate that A1 is child of C2. + * Step 1: Tansfer in C's nodes to Repo B * - * Step 1. Move A4 fron C2 to C3 via transfer. - * C2Dest should stop being invaded C3Dest should be invaded. + * Step 2. Transfer in A's nodes to Repo B + * + * Setup tree above. Validate that A2 is child of C2 dest. + * A4 is a child of B1 + * + * Step 3. Move A5 from C2 to C3 via transfer. + * C2Dest should stop being invaded by A5, C3Dest should be invaded by A5. + * + * Step 4. Invade A5 by B6. Move from C3 to C2 via transfer. + * C2Dest should be invaded by A and B. + * C3Dest should not be invaded. + * + * Step 5. Move A5 to A4. + * A4 should be invaded by B due to B6 but not by A. + * C2Dest should not be invaded. */ public void testMultiRepoTransferMove() throws Exception { @@ -5063,6 +5445,8 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest NodeRef C2NodeRef; NodeRef C3NodeRef; NodeRef A4NodeRef; + NodeRef A5NodeRef; + NodeRef B6NodeRef; NodeRef C2DummyNodeRef; NodeRef C3DummyNodeRef; QName C2Path = QName.createQName("p2"); @@ -5148,10 +5532,18 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest { // Node A4 - ChildAssociationRef child = nodeService.createNode(C2DummyNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("C4"), ContentModel.TYPE_FOLDER); + ChildAssociationRef child = nodeService.createNode(A1NodeRef, 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"); + nodeService.setProperty(A4NodeRef, ContentModel.PROP_TITLE, "A4"); + nodeService.setProperty(A4NodeRef, ContentModel.PROP_NAME, "A4"); + } + + { + // Node A5 + ChildAssociationRef child = nodeService.createNode(C2DummyNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A5"), ContentModel.TYPE_FOLDER); + A5NodeRef = child.getChildRef(); + nodeService.setProperty(A5NodeRef, ContentModel.PROP_TITLE, "A5"); + nodeService.setProperty(A5NodeRef, ContentModel.PROP_NAME, "A5"); } // Create the transfer target if it does not already exist @@ -5240,6 +5632,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest TransferDefinition definition = new TransferDefinition(); Collection nodes = new ArrayList(); nodes.add(A4NodeRef); + nodes.add(A5NodeRef); definition.setNodes(nodes); definition.setSync(true); transferService.transfer(targetName, definition); @@ -5252,14 +5645,17 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest startNewTransaction(); try { - assertTrue("dest node A4 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(A4NodeRef))); + assertTrue("dest node A5 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(A5NodeRef))); 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)); + ChildAssociationRef A5Ref = nodeService.getPrimaryParent(testNodeFactory.getMappedNodeRef(A5NodeRef)); + assertEquals("A5 dest is connected to the wrong node", A5Ref.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)); + + ChildAssociationRef A4Ref = nodeService.getPrimaryParent(testNodeFactory.getMappedNodeRef(A4NodeRef)); + assertEquals("A4 dest is connected to the wrong node", A4Ref.getParentRef(), B1NodeRef); + } finally { @@ -5269,12 +5665,12 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest /** * Step 3 * Now move A3 - * C2 (Dest) gets invaded by A4 + * C2 (Dest) gets invaded by A5 */ startNewTransaction(); try { - nodeService.moveNode(A4NodeRef, C3DummyNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("C4")); + nodeService.moveNode(A5NodeRef, C3DummyNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("C4")); } finally { @@ -5286,7 +5682,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest { TransferDefinition definition = new TransferDefinition(); Collection nodes = new ArrayList(); - nodes.add(A4NodeRef); + nodes.add(A5NodeRef); definition.setNodes(nodes); definition.setSync(true); transferService.transfer(targetName, definition); @@ -5299,14 +5695,14 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest startNewTransaction(); try { - assertTrue("dest node A4 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(A4NodeRef))); + assertTrue("dest node A5 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(A5NodeRef))); 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)); + ChildAssociationRef A5Ref = nodeService.getPrimaryParent(testNodeFactory.getMappedNodeRef(A5NodeRef)); + assertEquals("A5 dest is connected to the wrong node", A5Ref.getParentRef(), testNodeFactory.getMappedNodeRef(C3NodeRef)); + assertTrue("A5 dest is not invaded", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(A5NodeRef), 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)); } @@ -5314,17 +5710,122 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest { endTransaction(); } - + + /** + * Step 4 - multi invasion move via transfer service. + * Invade A5 by B6. Transfer from C3 back to C2. + */ + startNewTransaction(); + try + { + nodeService.moveNode(A5NodeRef, C2DummyNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B6")); + + // Node B5 + ChildAssociationRef child = nodeService.createNode(testNodeFactory.getMappedNodeRef(A5NodeRef), ContentModel.ASSOC_CONTAINS, QName.createQName("B6"), ContentModel.TYPE_FOLDER); + B6NodeRef = child.getChildRef(); + nodeService.setProperty(B6NodeRef, ContentModel.PROP_TITLE, "B6"); + nodeService.setProperty(B6NodeRef, ContentModel.PROP_NAME, "B6"); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + TransferDefinition definition = new TransferDefinition(); + Collection nodes = new ArrayList(); + nodes.add(A5NodeRef); + definition.setNodes(nodes); + definition.setSync(true); + transferService.transfer(targetName, definition); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + assertTrue("dest node A5 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(A5NodeRef))); + 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 A5Ref = nodeService.getPrimaryParent(testNodeFactory.getMappedNodeRef(A5NodeRef)); + ChildAssociationRef B6Ref = nodeService.getPrimaryParent(B6NodeRef); + assertEquals("A5 dest is connected to the wrong node", A5Ref.getParentRef(), testNodeFactory.getMappedNodeRef(C2NodeRef)); + assertEquals("B6 connected to the wrong node", B6Ref.getParentRef(), testNodeFactory.getMappedNodeRef(A5NodeRef)); + assertTrue("A5 dest is not invaded", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(A5NodeRef), TransferModel.ASPECT_ALIEN)); + assertTrue("C2 dest is not invaded", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(C2NodeRef), TransferModel.ASPECT_ALIEN)); + assertFalse("C3 dest is still invaded", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(C3NodeRef), TransferModel.ASPECT_ALIEN)); + Listinvaders = (List)nodeService.getProperty(testNodeFactory.getMappedNodeRef(C2NodeRef), TransferModel.PROP_INVADED_BY); + assertTrue("invaders is too small", invaders.size() > 1); + assertTrue("invaders does not contain REPO A", invaders.contains(REPO_ID_A)); + } + finally + { + endTransaction(); + } + + /** + * Step 5 + * Move + */ + startNewTransaction(); + try + { + nodeService.moveNode(A5NodeRef, A4NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A5")); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + TransferDefinition definition = new TransferDefinition(); + Collection nodes = new ArrayList(); + nodes.add(A5NodeRef); + definition.setNodes(nodes); + definition.setSync(true); + transferService.transfer(targetName, definition); + } + finally + { + endTransaction(); + } + + startNewTransaction(); + try + { + assertTrue("dest node A5 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(A5NodeRef))); + 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 A5dest is a child of A4Dest which is a child of B1 + ChildAssociationRef A5Ref = nodeService.getPrimaryParent(testNodeFactory.getMappedNodeRef(A5NodeRef)); + assertEquals("A5 dest is connected to the wrong node", A5Ref.getParentRef(), testNodeFactory.getMappedNodeRef(A4NodeRef)); + assertTrue("A4 dest is not invaded", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(A4NodeRef), TransferModel.ASPECT_ALIEN)); + assertTrue("A5 dest is not invaded", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(A5NodeRef), TransferModel.ASPECT_ALIEN)); + assertTrue("B6 dest is not invaded", nodeService.hasAspect(B6NodeRef, TransferModel.ASPECT_ALIEN)); + assertFalse("C2 dest is still invaded", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(C2NodeRef), TransferModel.ASPECT_ALIEN)); + assertFalse("C3 dest is still invaded", nodeService.hasAspect(testNodeFactory.getMappedNodeRef(C3NodeRef), TransferModel.ASPECT_ALIEN)); + + Listinvaders = (List)nodeService.getProperty(testNodeFactory.getMappedNodeRef(A4NodeRef), TransferModel.PROP_INVADED_BY); + assertTrue("invaders is too big", invaders.size() < 2); + assertFalse("invaders contains REPO A", invaders.contains(REPO_ID_A)); + + } + 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) { if (this.authenticationService.authenticationExists(userName) == false)