+ * Alien nodes cannot be deleted through the transfer service, instead they are
+ * "pruned"
+ *
+ *
+ * This class owns the aspect trx:alien (TransferModel.ASPECT_ALIEN)
+ */
+public interface AlienProcessor
+{
+ /**
+ * Prune the given node of aliens from the specified repositoryId
+ * @param parentNodeRef the root to prune
+ * @param fromRepositoryId the repositoryId to prune.
+ */
+ public void pruneNode(NodeRef parentNodeRef, String fromRepositoryId);
+
+ /**
+ * Has the node been invaded by aliens ?
+ * @param nodeRef the node to check
+ * @return true the node has been invaded by aliens.
+ */
+ 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.
+ *
+ * @param childAssocRef the association ref to the new node
+ * @param repositoryId - the repositoryId of the system who owns the new node.
+ */
+ public void onCreateChild(ChildAssociationRef childAssocRef, String repositoryId);
+
+}
diff --git a/source/java/org/alfresco/repo/transfer/AlienProcessorImpl.java b/source/java/org/alfresco/repo/transfer/AlienProcessorImpl.java
new file mode 100644
index 0000000000..cd1c7d3534
--- /dev/null
+++ b/source/java/org/alfresco/repo/transfer/AlienProcessorImpl.java
@@ -0,0 +1,497 @@
+package org.alfresco.repo.transfer;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Stack;
+import java.util.Vector;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.repo.node.NodeServicePolicies;
+import org.alfresco.repo.policy.BehaviourFilter;
+import org.alfresco.repo.policy.JavaBehaviour;
+import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
+import org.alfresco.repo.security.authentication.AuthenticationUtil;
+import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
+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.namespace.QName;
+import org.alfresco.util.PropertyCheck;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Class to encapsulate the behaviour of "Alien" nodes.
+ */
+public class AlienProcessorImpl implements AlienProcessor
+{
+ private NodeService nodeService;
+ private BehaviourFilter behaviourFilter;
+ private DictionaryService dictionaryService;
+
+ private static final Log log = LogFactory.getLog(AlienProcessorImpl.class);
+
+ public void init()
+ {
+ PropertyCheck.mandatory(this, "nodeService", nodeService);
+ PropertyCheck.mandatory(this, "behaviourFilter", behaviourFilter);
+ PropertyCheck.mandatory(this, "dictionaryService", getDictionaryService());
+ }
+
+ public void onCreateChild(ChildAssociationRef childAssocRef, final String repositoryId)
+ {
+ log.debug("on create child association to transferred node");
+
+ ChildAssociationRef currentAssoc = childAssocRef;
+
+ 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
+ if(!childAssocRef.getTypeQName().equals(ContentModel.ASSOC_CONTAINS))
+ {
+ Collection subAspects = dictionaryService.getSubAspects(ContentModel.ASSOC_CONTAINS, true);
+ if(!subAspects.contains(childAssocRef.getTypeQName()))
+ {
+ log.debug("not a subtype of cm:contains - do nothing");
+ return;
+ }
+ }
+
+ NodeRef parentNodeRef = currentAssoc.getParentRef();
+ NodeRef childNodeRef = currentAssoc.getChildRef();
+
+ if(!nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED))
+ {
+ log.debug("parent was not transferred - do nothing");
+ return;
+ }
+
+ if(!nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_ALIEN))
+ {
+ // parent is not yet an alien invader ...
+ String parentFromRepo = (String)nodeService.getProperty(parentNodeRef, TransferModel.PROP_FROM_REPOSITORY_ID);
+ {
+ if(repositoryId.equalsIgnoreCase(parentFromRepo))
+ {
+ log.debug("parent was not alien and this node is from the same repo - do nothing");
+ return;
+ }
+ }
+ }
+
+ /**
+ * If we get this far then we are going to Make the new child node
+ * an alien node
+ */
+ setAlien(childNodeRef, repositoryId);
+
+ /**
+ * 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, repositoryId))
+ {
+ if(log.isDebugEnabled())
+ {
+ log.debug("alien invades parent node:" + parentNodeRef + ", repositoryId:" + repositoryId);
+ }
+
+ 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
+ {
+ getBehaviourFilter().disableBehaviour(newAlien, ContentModel.ASPECT_AUDITABLE);
+ getBehaviourFilter().disableBehaviour(newAlien, ContentModel.ASPECT_LOCKABLE);
+ setAlien(newAlien, repositoryId);
+ 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;
+ }
+ }
+ }
+
+ public void beforeDeleteAlien(NodeRef deletedNodeRef)
+ {
+ log.debug("on delete node - need to check for transferred node");
+
+ 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 is no longer alien nodeRef" + oldAlien);
+ 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
+ }
+
+ public boolean isAlien(NodeRef nodeRef)
+ {
+ return nodeService.hasAspect(nodeRef, TransferModel.ASPECT_ALIEN);
+ }
+
+ public 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(getNodeService().hasAspect(currentNodeRef, TransferModel.ASPECT_ALIEN))
+ {
+ // Yes this is an alien node
+ ListinvadedBy = (List)getNodeService().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);
+ getNodeService().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 = getNodeService().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
+ */
+ getNodeService().hasAspect(currentNodeRef, TransferModel.ASPECT_TRANSFERRED);
+ {
+ String fromRepoId = (String)getNodeService().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 = 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());
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // Current node does not contain alien nodes so it can be deleted.
+ getNodeService().hasAspect(currentNodeRef, TransferModel.ASPECT_TRANSFERRED);
+ {
+ String fromRepoId = (String)getNodeService().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);
+ getNodeService().deleteNode(currentNodeRef);
+ }
+ }
+ }
+ }
+
+ /**
+ * Now ripple the "invadedBy" flag upwards.
+ */
+
+ 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)
+ {
+ NodeRef childNode = ref.getChildRef();
+ ListchildInvadedBy = (List)getNodeService().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);
+ getNodeService().setProperty(folderNodeRef, TransferModel.PROP_INVADED_BY, (Serializable)newInvadedBy);
+ }
+ }
+ log.debug("pruneNode: end");
+ }
+
+
+ /**
+ * 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 setNodeService(NodeService nodeService)
+ {
+ this.nodeService = nodeService;
+ }
+
+ public NodeService getNodeService()
+ {
+ return nodeService;
+ }
+
+ public void setBehaviourFilter(BehaviourFilter behaviourFilter)
+ {
+ this.behaviourFilter = behaviourFilter;
+ }
+
+ public BehaviourFilter getBehaviourFilter()
+ {
+ return behaviourFilter;
+ }
+
+ public void setDictionaryService(DictionaryService dictionaryService)
+ {
+ this.dictionaryService = dictionaryService;
+ }
+
+ public DictionaryService getDictionaryService()
+ {
+ return dictionaryService;
+ }
+}
diff --git a/source/java/org/alfresco/repo/transfer/DefaultManifestProcessorFactoryImpl.java b/source/java/org/alfresco/repo/transfer/DefaultManifestProcessorFactoryImpl.java
index c58d2cc81a..17734500c7 100644
--- a/source/java/org/alfresco/repo/transfer/DefaultManifestProcessorFactoryImpl.java
+++ b/source/java/org/alfresco/repo/transfer/DefaultManifestProcessorFactoryImpl.java
@@ -40,6 +40,7 @@ public class DefaultManifestProcessorFactoryImpl implements ManifestProcessorFac
private DictionaryService dictionaryService;
private PermissionService permissionService;
private CorrespondingNodeResolverFactory nodeResolverFactory;
+ private AlienProcessor alienProcessor;
/*
* (non-Javadoc)
@@ -57,6 +58,7 @@ public class DefaultManifestProcessorFactoryImpl implements ManifestProcessorFac
primaryProcessor.setNodeService(nodeService);
primaryProcessor.setDictionaryService(dictionaryService);
primaryProcessor.setPermissionService(getPermissionService());
+ primaryProcessor.setAlienProcessor(getAlienProcessor());
processors.add(primaryProcessor);
RepoSecondaryManifestProcessorImpl secondaryProcessor = new RepoSecondaryManifestProcessorImpl(receiver, transferId);
@@ -65,8 +67,8 @@ public class DefaultManifestProcessorFactoryImpl implements ManifestProcessorFac
processors.add(secondaryProcessor);
RepoTertiaryManifestProcessorImpl tertiaryProcessor = new RepoTertiaryManifestProcessorImpl(receiver, transferId);
- tertiaryProcessor.setNodeResolver(nodeResolver);
tertiaryProcessor.setNodeService(nodeService);
+ tertiaryProcessor.setAlienProcessor(getAlienProcessor());
processors.add(tertiaryProcessor);
return processors;
@@ -113,8 +115,7 @@ public class DefaultManifestProcessorFactoryImpl implements ManifestProcessorFac
{
RepoRequsiteManifestProcessorImpl processor = new RepoRequsiteManifestProcessorImpl(receiver, transferId, out);
- CorrespondingNodeResolver nodeResolver = nodeResolverFactory.getResolver();
-
+ CorrespondingNodeResolver nodeResolver = nodeResolverFactory.getResolver();
processor.setNodeResolver(nodeResolver);
processor.setNodeService(nodeService);
@@ -131,4 +132,14 @@ public class DefaultManifestProcessorFactoryImpl implements ManifestProcessorFac
return permissionService;
}
+ public void setAlienProcessor(AlienProcessor alienProcessor)
+ {
+ this.alienProcessor = alienProcessor;
+ }
+
+ public AlienProcessor getAlienProcessor()
+ {
+ return alienProcessor;
+ }
+
}
diff --git a/source/java/org/alfresco/repo/transfer/RepoPrimaryManifestProcessorImpl.java b/source/java/org/alfresco/repo/transfer/RepoPrimaryManifestProcessorImpl.java
index d3410d9272..fb2f6ae148 100644
--- a/source/java/org/alfresco/repo/transfer/RepoPrimaryManifestProcessorImpl.java
+++ b/source/java/org/alfresco/repo/transfer/RepoPrimaryManifestProcessorImpl.java
@@ -89,6 +89,7 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
private ContentService contentService;
private DictionaryService dictionaryService;
private CorrespondingNodeResolver nodeResolver;
+ private AlienProcessor alienProcessor;
// State within this class
/**
@@ -148,18 +149,35 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
// Does a corresponding node exist in this repo?
if (resolvedNodes.resolvedChild != null)
{
+ 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 " + resolvedNodes.resolvedChild
+ + " has been resolved to existing local noderef " + exNode
+ " - deleting");
}
- logProgress("Deleting local node: " + resolvedNodes.resolvedChild);
- nodeService.deleteNode(resolvedNodes.resolvedChild);
- if (log.isDebugEnabled())
+
+ //TODO : do we have a business rule that only the "from" repo can delete a node? Yes we do.
+ if(alienProcessor.isAlien(exNode))
{
- log.debug("Deleted local node: " + resolvedNodes.resolvedChild);
+ 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
@@ -204,7 +222,7 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
// Does a corresponding node exist in this repo?
if (resolvedNodes.resolvedChild != null)
{
- // Yes, it does. Update it.
+ // Yes, the corresponding node does exist. Update it.
if (log.isDebugEnabled())
{
log.debug("Incoming noderef " + node.getNodeRef() + " has been resolved to existing local noderef "
@@ -214,8 +232,7 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
}
else
{
- // No, there is no corresponding node. Worth just quickly checking
- // the archive store...
+ // No, there is no corresponding node.
NodeRef archiveNodeRef = new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, node.getNodeRef().getId());
if (nodeService.exists(archiveNodeRef))
{
@@ -240,6 +257,7 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
}
/**
+ * Create new node.
*
* @param node
* @param resolvedNodes
@@ -285,14 +303,12 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
// Split out the content properties and sanitise the others
Map contentProps = processProperties(null, props, null);
- // inject transferred property here
- if(!contentProps.containsKey(TransferModel.PROP_REPOSITORY_ID))
- {
- log.debug("injecting repositoryId property");
- props.put(TransferModel.PROP_REPOSITORY_ID, header.getRepositoryId());
- }
- props.put(TransferModel.PROP_FROM_REPOSITORY_ID, header.getRepositoryId());
-
+ injectTransferred(props);
+
+ // Remove the invadedBy property since that is used by the transfer service
+ // and is local to this repository.
+ props.remove(TransferModel.PROP_INVADED_BY);
+
// Do we need to worry about locking this new node ?
if(header.isReadOnly())
{
@@ -305,12 +321,12 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
// Create the corresponding node...
ChildAssociationRef newNode = nodeService.createNode(parentNodeRef, parentAssocType, parentAssocName, node
.getType(), props);
-
+
if (log.isDebugEnabled())
{
log.debug("Created new node (" + newNode.getChildRef() + ") parented by node " + newNode.getParentRef());
}
-
+
// Deal with the content properties
writeContent(newNode.getChildRef(), contentProps);
@@ -323,7 +339,6 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
nodeService.addAspect(newNode.getChildRef(), aspect, null);
}
-
ManifestAccessControl acl = node.getAccessControl();
// Apply new ACL to this node
if(acl != null)
@@ -344,6 +359,15 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
}
}
}
+
+ /**
+ * are we adding an alien node here? The transfer service has policies disabled
+ * so have to call the consequence of the policy directly.
+ */
+ if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED))
+ {
+ alienProcessor.onCreateChild(newNode, header.getRepositoryId());
+ }
// Is the node that we've just added the parent of any orphans that
// we've found earlier?
@@ -359,8 +383,16 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
for (ChildAssociationRef orphan : orphansToClaim)
{
logProgress("Re-parenting previously orphaned node (" + orphan.getChildRef() + ") with found parent " + orphan.getParentRef());
- nodeService.moveNode(orphan.getChildRef(), orphan.getParentRef(), orphan.getTypeQName(), orphan
+ ChildAssociationRef newRef = nodeService.moveNode(orphan.getChildRef(), orphan.getParentRef(), orphan.getTypeQName(), orphan
.getQName());
+
+ /**
+ * We may be creating an alien node here and the policies are turned off.
+ */
+ if(nodeService.hasAspect(newRef.getParentRef(), TransferModel.ASPECT_TRANSFERRED))
+ {
+ alienProcessor.onCreateChild(newRef, header.getRepositoryId());
+ }
}
// We can now remove the record of these orphans, as their parent
// has been found
@@ -402,9 +434,25 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
|| !currentParent.getTypeQName().equals(parentAssocType)
|| !currentParent.getQName().equals(parentAssocName))
{
+
+ /**
+ * 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))
+ {
+ alienProcessor.beforeDeleteAlien(node.getNodeRef());
+ }
+
// Yes, we need to move the node
- nodeService.moveNode(nodeToUpdate, parentNodeRef, parentAssocType, parentAssocName);
+ 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());
+ }
}
log.info("Resolved parent node to " + parentNodeRef);
@@ -418,12 +466,18 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
Map existingProps = nodeService.getProperties(nodeToUpdate);
// inject transferred property here
- if(!props.containsKey(TransferModel.PROP_REPOSITORY_ID))
- {
- log.debug("injecting repositoryId property");
- props.put(TransferModel.PROP_REPOSITORY_ID, header.getRepositoryId());
- }
- props.put(TransferModel.PROP_FROM_REPOSITORY_ID, header.getRepositoryId());
+ injectTransferred(props);
+
+// if(!props.containsKey(TransferModel.PROP_REPOSITORY_ID))
+// {
+// log.debug("injecting repositoryId property");
+// props.put(TransferModel.PROP_REPOSITORY_ID, header.getRepositoryId());
+// }
+// props.put(TransferModel.PROP_FROM_REPOSITORY_ID, header.getRepositoryId());
+
+ // Remove the invadedBy property since that is used by the transfer service
+ // and is local to this repository.
+ props.remove(TransferModel.PROP_INVADED_BY);
// Do we need to worry about locking this updated ?
if(header.isReadOnly())
@@ -436,6 +490,12 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
// Split out the content properties and sanitise the others
Map contentProps = processProperties(nodeToUpdate, props, existingProps);
+
+ // If there was already a value for invadedBy then leave it alone rather than replacing it.
+ if(existingProps.containsKey(TransferModel.PROP_INVADED_BY))
+ {
+ props.put(TransferModel.PROP_INVADED_BY, existingProps.get(TransferModel.PROP_INVADED_BY));
+ }
// Update the non-content properties
nodeService.setProperties(nodeToUpdate, props);
@@ -461,7 +521,13 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
}
aspectsToRemove.removeAll(suppliedAspects);
+
+ /**
+ * Don't remove the aspects that the transfer service uses itself.
+ */
aspectsToRemove.remove(TransferModel.ASPECT_TRANSFERRED);
+ aspectsToRemove.remove(TransferModel.ASPECT_ALIEN);
+
suppliedAspects.removeAll(existingAspects);
// Now aspectsToRemove contains the set of aspects to remove
@@ -541,6 +607,7 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
}
}
}
+
/**
* This method takes all the received properties and separates them into two parts. The content properties are
@@ -798,4 +865,27 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
return permissionService;
}
+ /**
+ * inject transferred
+ */
+ private void injectTransferred(Map props)
+ {
+ if(!props.containsKey(TransferModel.PROP_REPOSITORY_ID))
+ {
+ log.debug("injecting repositoryId property");
+ props.put(TransferModel.PROP_REPOSITORY_ID, header.getRepositoryId());
+ }
+ props.put(TransferModel.PROP_FROM_REPOSITORY_ID, header.getRepositoryId());
+ }
+
+ public void setAlienProcessor(AlienProcessor alienProcessor)
+ {
+ this.alienProcessor = alienProcessor;
+ }
+
+ public AlienProcessor getAlienProcessor()
+ {
+ return alienProcessor;
+ }
+
}
diff --git a/source/java/org/alfresco/repo/transfer/RepoSecondaryManifestProcessorImpl.java b/source/java/org/alfresco/repo/transfer/RepoSecondaryManifestProcessorImpl.java
index 2022c10f3c..aed60e2b9b 100644
--- a/source/java/org/alfresco/repo/transfer/RepoSecondaryManifestProcessorImpl.java
+++ b/source/java/org/alfresco/repo/transfer/RepoSecondaryManifestProcessorImpl.java
@@ -40,10 +40,10 @@ import org.alfresco.service.namespace.RegexQNamePattern;
*
* The secondary manifest processor performs a second parse of the snapshot file.
*
- * It is responsible for linking nodes together, moving them out of the temporary space
- * into their final position in the repository. At the point that this processor runs both
- * ends (source and target) of the nodes' associations should be available in the receiving
- * repository.
+ * It is responsible for linking nodes together.
+ *
+ * At the point that this processor runs both ends (source and target) of the nodes' associations should be
+ * available in the receiving repository.
*
*/
public class RepoSecondaryManifestProcessorImpl extends AbstractManifestProcessorBase
diff --git a/source/java/org/alfresco/repo/transfer/RepoTertiaryManifestProcessorImpl.java b/source/java/org/alfresco/repo/transfer/RepoTertiaryManifestProcessorImpl.java
index 3bfb02c08b..19686dbb18 100644
--- a/source/java/org/alfresco/repo/transfer/RepoTertiaryManifestProcessorImpl.java
+++ b/source/java/org/alfresco/repo/transfer/RepoTertiaryManifestProcessorImpl.java
@@ -19,10 +19,12 @@
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;
@@ -46,12 +48,11 @@ import org.apache.commons.logging.LogFactory;
* which exist in the target repository that do not exist in the source repository.
*
* If the transfer is not "sync" then this processor does nothing.
- *
*/
public class RepoTertiaryManifestProcessorImpl extends AbstractManifestProcessorBase
{
private NodeService nodeService;
- private CorrespondingNodeResolver nodeResolver;
+ private AlienProcessor alienProcessor;
private static final Log log = LogFactory.getLog(RepoTertiaryManifestProcessorImpl.class);
@@ -83,7 +84,7 @@ public class RepoTertiaryManifestProcessorImpl extends AbstractManifestProcessor
protected void processNode(TransferManifestNormalNode node)
{
NodeRef nodeRef = node.getNodeRef();
- log.debug("processNode " + nodeRef);
+ log.debug("processNode : " + nodeRef);
if(isSync)
{
@@ -94,7 +95,10 @@ public class RepoTertiaryManifestProcessorImpl extends AbstractManifestProcessor
for(ChildAssociationRef ref : expectedChildren)
{
- log.debug("expecting child" + ref);
+ if(log.isDebugEnabled())
+ {
+ log.debug("expecting child" + ref);
+ }
expectedChildNodeRefs.add(ref.getChildRef());
}
@@ -103,6 +107,7 @@ public class RepoTertiaryManifestProcessorImpl extends AbstractManifestProcessor
if(nodeService.exists(nodeRef))
{
log.debug("destination node exists");
+
/**
* yes this node exists in the destination.
*/
@@ -126,8 +131,10 @@ public class RepoTertiaryManifestProcessorImpl extends AbstractManifestProcessor
{
/**
* An unexpected child - if this node has been transferred then
- * it needs to be deleted. If it is a local node then we don't
- * touch it.
+ * it needs to be deleted.
+ *
+ * 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))
@@ -141,10 +148,22 @@ public class RepoTertiaryManifestProcessorImpl extends AbstractManifestProcessor
if(manifestRepositoryId.equalsIgnoreCase(fromRepositoryId))
{
// Yes the manifest repository Id and the from repository Id match.
-
- // Destination node needs to be deleted.
- nodeService.deleteNode(childNodeRef);
- log.debug("deleted node:" + childNodeRef);
+ 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);
+ //pruneNode(childNodeRef, fromRepositoryId);
+ }
+ else
+ {
+ // Destination node needs to be deleted.
+ nodeService.deleteNode(childNodeRef);
+ log.debug("deleted node:" + childNodeRef);
+ }
}
}
}
@@ -182,13 +201,169 @@ 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");
+// }
- /**
- * @param nodeResolver
- * the nodeResolver to set
- */
- public void setNodeResolver(CorrespondingNodeResolver nodeResolver)
+ public void setAlienProcessor(AlienProcessor alienProcessor)
{
- this.nodeResolver = nodeResolver;
+ this.alienProcessor = alienProcessor;
+ }
+
+ public AlienProcessor getAlienProcessor()
+ {
+ return alienProcessor;
}
}
diff --git a/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImpl.java b/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImpl.java
index 994dff19e6..edcf1ec898 100644
--- a/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImpl.java
+++ b/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImpl.java
@@ -28,10 +28,13 @@ import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.io.Writer;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import javax.xml.parsers.SAXParser;
@@ -67,6 +70,7 @@ import org.alfresco.service.cmr.transfer.TransferException;
import org.alfresco.service.cmr.transfer.TransferProgress;
import org.alfresco.service.cmr.transfer.TransferReceiver;
import org.alfresco.service.cmr.transfer.TransferProgress.Status;
+import org.alfresco.service.descriptor.DescriptorService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
@@ -158,6 +162,10 @@ public class RepoTransferReceiverImpl implements TransferReceiver,
private TenantService tenantService;
private RuleService ruleService;
private PolicyComponent policyComponent;
+ private DescriptorService descriptorService;
+ private AlienProcessor alienProcessor;
+
+ //private String localRepositoryId = descriptorService.getCurrentRepositoryDescriptor().getId();
private Map transferLockFolderMap = new ConcurrentHashMap();
private Map transferTempFolderMap = new ConcurrentHashMap();
@@ -176,17 +184,24 @@ public class RepoTransferReceiverImpl implements TransferReceiver,
PropertyCheck.mandatory(this, "inboundTransferRecordsPath", inboundTransferRecordsPath);
PropertyCheck.mandatory(this, "rootStagingDirectory", rootStagingDirectory);
PropertyCheck.mandatory(this, "policyComponent", policyComponent);
+ PropertyCheck.mandatory(this, "descriptorService", descriptorService);
+ PropertyCheck.mandatory(this, "alienProcessor", alienProcessor);
-// // Register policy behaviours
-// this.getPolicyComponent().bindAssociationBehaviour(
-// NodeServicePolicies.OnCreateChildAssociationPolicy.QNAME,
-// TransferModel.ASPECT_TRANSFERRED,
-// new JavaBehaviour(this, "onCreateChildAssociation", NotificationFrequency.EVERY_EVENT));
-//
-// this.getPolicyComponent().bindClassBehaviour(
-// NodeServicePolicies.BeforeDeleteNodePolicy.QNAME,
-// this,
-// new JavaBehaviour(this, "beforeDeleteNode", NotificationFrequency.EVERY_EVENT));
+ /**
+ * For every new child of a node with the trx:transferred aspect run this.onCreateChildAssociation
+ */
+ this.getPolicyComponent().bindAssociationBehaviour(
+ NodeServicePolicies.OnCreateChildAssociationPolicy.QNAME,
+ TransferModel.ASPECT_TRANSFERRED,
+ 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));
}
@@ -859,14 +874,19 @@ public class RepoTransferReceiverImpl implements TransferReceiver,
}
/**
- * @param progressMonitor
- * the progressMonitor to set
+ * Set the ruleService
+ * @param ruleService
+ * the ruleService to set
*/
public void setRuleService(RuleService ruleService)
{
this.ruleService = ruleService;
}
+ /**
+ * Get the rule service
+ * @return the rule service
+ */
public RuleService getRuleService()
{
return this.ruleService;
@@ -935,10 +955,11 @@ public class RepoTransferReceiverImpl implements TransferReceiver,
}
/**
- * When a new node is created as a child of a Transferred node then
- * the transferred nodes need to be marked as Alien nodes.
- *
- * The tree needs to be walked upwards to mark all parent transferred nodes as alien.
+ * 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.
*/
public void onCreateChildAssociation(ChildAssociationRef childAssocRef,
boolean isNewNode)
@@ -946,75 +967,273 @@ public class RepoTransferReceiverImpl implements TransferReceiver,
log.debug("on create child association to transferred node");
- ChildAssociationRef ref = childAssocRef;
-
- if(childAssocRef.isPrimary())
- {
- while(ref != null)
- {
- NodeRef parentNodeRef = ref.getParentRef();
- NodeRef childNodeRef = ref.getChildRef();
-
- if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED))
- {
- Boolean isAlien = (Boolean)nodeService.getProperty(parentNodeRef, TransferModel.PROP_ALIEN);
-
- if (!isAlien)
- {
- log.debug("setting node as alien:" + parentNodeRef);
- nodeService.setProperty(parentNodeRef, TransferModel.PROP_ALIEN, Boolean.TRUE);
- ref = nodeService.getPrimaryParent(parentNodeRef);
- }
- else
- {
- log.debug("parent node is already alien");
- ref = null;
- }
- }
- else
- {
- log.debug("parent is not a transferred node");
- ref = null;
- }
- }
- }
+ 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;
+// }
+// }
+// }
}
/**
- * When an old node is deleted that is a child of a transferred node the tree may need to be walked to
- * mark parent folder as non alien.
+ * When an alien node is deleted the it may be the last alien invader
+ *
+ * Walk the tree checking the invasion status!
*/
- public void beforeDeleteNode(NodeRef nodeRef)
+ public void beforeDeleteNode(NodeRef deletedNodeRef)
{
log.debug("on delete node - need to check for transferred node");
-
- ChildAssociationRef ref = nodeService.getPrimaryParent(nodeRef);
-
- while(ref != null)
- {
- NodeRef parentNodeRef = ref.getParentRef();
-
- /**
- * Was the parent node transferred ?
- */
- if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED))
- {
- log.debug("parent node was transferred - check siblings");
-
- /**
- * Check the siblings of this node to see whether there are any other alien nodes.
- */
- // nodeService.getChildAssocs(parentNodeRef);
- // BUGBUG Code not complete
- ref = null;
-
-
- }
- else
- {
- log.debug("parent is not a transferred node");
- ref = null;
- }
- }
+ 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;
+ }
+
+ public DescriptorService getDescriptorService()
+ {
+ return descriptorService;
+ }
+
+ public void setAlienProcessor(AlienProcessor alienProcessor)
+ {
+ this.alienProcessor = alienProcessor;
+ }
+
+ public AlienProcessor getAlienProcessor()
+ {
+ return alienProcessor;
}
}
diff --git a/source/java/org/alfresco/repo/transfer/TransferModel.java b/source/java/org/alfresco/repo/transfer/TransferModel.java
index c2137786fb..f1e55163be 100644
--- a/source/java/org/alfresco/repo/transfer/TransferModel.java
+++ b/source/java/org/alfresco/repo/transfer/TransferModel.java
@@ -39,7 +39,14 @@ public interface TransferModel
static final QName ASPECT_TRANSFERRED = QName.createQName(TRANSFER_MODEL_1_0_URI, "transferred");
static final QName PROP_REPOSITORY_ID = QName.createQName(TRANSFER_MODEL_1_0_URI, "repositoryId");
static final QName PROP_FROM_REPOSITORY_ID = QName.createQName(TRANSFER_MODEL_1_0_URI, "fromRepositoryId");
+
+ /**
+ * Aspect : alien
+ */
+ 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");
+
/*
* Type : Transfer Group
*/
@@ -72,8 +79,7 @@ public interface TransferModel
static final QName PROP_PROGRESS_ENDPOINT = QName.createQName(TRANSFER_MODEL_1_0_URI, "progressEndpoint");
static final QName PROP_TRANSFER_STATUS = QName.createQName(TRANSFER_MODEL_1_0_URI, "transferStatus");
static final QName PROP_TRANSFER_ERROR = QName.createQName(TRANSFER_MODEL_1_0_URI, "transferError");
-
-
+
/*
* Type : Transfer report
*/
diff --git a/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java b/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java
index bc823a8cb6..923af3f49a 100644
--- a/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java
+++ b/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java
@@ -18,9 +18,11 @@
*/
package org.alfresco.repo.transfer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import java.util.ArrayList;
import java.util.Date;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@@ -35,12 +37,9 @@ import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
-import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
-import org.alfresco.repo.dictionary.DictionaryDAOImpl.DictionaryRegistry;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
-import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.transfer.manifest.TransferManifestNodeFactory;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.lock.LockService;
@@ -76,8 +75,6 @@ import org.alfresco.util.BaseAlfrescoSpringTest;
import org.alfresco.util.GUID;
import org.alfresco.util.Pair;
import org.alfresco.util.PropertyMap;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.util.ResourceUtils;
@@ -109,7 +106,9 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
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";
-
+ String REPO_ID_A = "RepoIdA";
+ String REPO_ID_B = "RepoIdB";
+ String REPO_ID_C = "RepoIdC";
@Override
public void runBare() throws Throwable
@@ -145,10 +144,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
authenticationComponent.setSystemUserAsCurrentUser();
setTransactionDefinition(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRES_NEW));
- assertNotNull("receiver is null", this.receiver);
-
-
-
+ assertNotNull("receiver is null", this.receiver);
}
/**
@@ -345,7 +341,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
}
/**
- * Test of Get All Trabsfer Targets By Group
+ * Test of Get All Transfer Targets By Group
*/
//TODO Test not complete - can't yet put targets in different groups
public void testGetAllTransferTargetsByGroup() throws Exception
@@ -605,6 +601,21 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
/**
* Test the transfer method by sending one node.
*
+ * Step 1: Create a new node (No content)
+ * transfer
+ *
+ * Step 2: Update Node title property
+ * transfer
+ *
+ * Step 3: Update Content property
+ * transfer
+ *
+ * Step 4: Transfer again
+ * transfer (Should transfer but not request the content item)
+ *
+ * Step 5: 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.
*/
public void testTransferOneNode() throws Exception
@@ -620,6 +631,8 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
* 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.
+ *
+ * Fake Repository Id
*/
TransferTransmitter transmitter = new UnitTestInProcessTransmitterImpl(receiver, contentService, transactionService);
transferServiceImpl.setTransmitter(transmitter);
@@ -628,7 +641,10 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
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);
+
/**
* Now go ahead and create our first transfer target
*/
@@ -657,11 +673,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
contentNodeRef = child.getChildRef();
nodeService.setProperty(contentNodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
nodeService.setProperty(contentNodeRef, ContentModel.PROP_NAME, name);
-
- ContentWriter writer = contentService.getWriter(contentNodeRef, ContentModel.PROP_CONTENT, true);
- writer.setLocale(CONTENT_LOCALE);
- writer.putContent(CONTENT_STRING);
-
+
if(!transferService.targetExists(targetName))
{
transferMe = createTransferTarget(targetName);
@@ -681,7 +693,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
try
{
/**
- * Transfer our transfer target node which has no content
+ * Step 1: Transfer our node which has no content
*/
{
TransferDefinition definition = new TransferDefinition();
@@ -718,8 +730,6 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
logger.debug("srcCreatedDate : " + srcCreatedDate + " destCreatedDate : " + destCreatedDate);
assertTrue("dest created date is not correct", destCreatedDate.compareTo(srcCreatedDate)== 0);
-
-
// Check injected transferred aspect.
assertNotNull("transferredAspect", (String)nodeService.getProperty(destNodeRef, TransferModel.PROP_REPOSITORY_ID));
@@ -737,6 +747,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
try
{
/**
+ * Step 2:
* Transfer our node again - so this is an update of the title property
*/
{
@@ -777,17 +788,22 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
// Check injected transferred aspect.
assertNotNull("transferredAspect", (String)nodeService.getProperty(destNodeRef, TransferModel.PROP_REPOSITORY_ID));
+ ContentWriter writer = contentService.getWriter(contentNodeRef, ContentModel.PROP_CONTENT, true);
+ writer.setLocale(CONTENT_LOCALE);
+ writer.putContent(CONTENT_STRING);
+
}
finally
{
endTransaction();
}
- logger.debug("Transfer again - this is an update");
+ logger.debug("Transfer again - this is an update with new content");
startNewTransaction();
try
{
/**
+ * Step 3:
* Transfer our node again - so this is an update
*/
{
@@ -804,6 +820,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
}
/**
+ * Step 4:
* Now transfer nothing - content items do not need to be transferred since its already on
* the destination.
*/
@@ -841,6 +858,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
}
/**
+ * Step 5
* Negative test transfer nothing
*/
logger.debug("Transfer again - with no content - should throw exception");
@@ -897,6 +915,9 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
// 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);
+
TransferTarget transferMe;
startNewTransaction();
@@ -1159,7 +1180,11 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
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 CONTENT_TITLE = "ContentTitle";
String CONTENT_TITLE_UPDATED = "ContentTitleUpdated";
String CONTENT_NAME = GUID.generate();
@@ -1316,7 +1341,10 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
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);
+
/**
* Now go ahead and create our first transfer target
* This needs to be committed before we can call transfer asycnc.
@@ -1524,7 +1552,10 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
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);
+
/**
* Now go ahead and create our first transfer target
* This needs to be committed before we can call transfer asycnc.
@@ -1756,7 +1787,10 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
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);
+
/**
* Now go ahead and create our first transfer target
* This needs to be committed before we can call transfer asycnc.
@@ -2031,7 +2065,10 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
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);
+
/**
* Now go ahead and create our first transfer target
*/
@@ -2695,637 +2732,749 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
}
-// /**
-// * Test the transfer method behaviour with respect to sync with alien nodes.
-// *
-// * In general an alien node will prevent deletion of the parent folders
-// *
-// * This is a unit test so it does some shenanigans to send to the same instance of alfresco.
-// *
-// * Tree of nodes
-// *
-// * A1
-// * | | |
-// * 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
-// *
-// * Test steps -
-// * 1 add A1, A2, A3, A4, A5, A6, A7, A8
-// * transfer(sync)
-// * 2 add Alien node B9. A1 becomes Alien.
-// * 3 remove alien node B9. A1 becomes non Alien.
-// * 4 add Alien node B10. A1 and A2 become Alien
-// * 5 remove Alien node B10. A1 and A2 become non Alien
-// * 6 add B12 A6, A2, A1 becomes Alien
-// * 7 add B13 A6, A2, A1 remains Alien
-// * 8 remove B13 A6, A2, A1 remains Alien
-// * 9 remove B12 A6, A2, A1 becomes non Alien.
-// * 10 add B9 and B10 A1 and A2 become Alien
-// * 11 remove B10 A2 becomes non alien A1 remains alien.
-// * 12 delete A2 containing alien node B11
-// * transfer
-// * (A5, A6, A7 and A8 should be deleted A2 and A4 remain since they contain alien content.)
-// *
-// */
-// public void testSyncWithAlienNodes() throws Exception
-// {
-// setDefaultRollback(false);
-//
-// String CONTENT_TITLE = "ContentTitle";
-// String CONTENT_TITLE_UPDATED = "ContentTitleUpdated";
-// Locale CONTENT_LOCALE = Locale.JAPAN;
-// 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)));
-//
-// /**
-// * Now go ahead and create our first transfer target
-// */
-// String targetName = "testSyncWithAlienNodes";
-// TransferTarget transferMe;
-//
-// NodeRef A1NodeRef;
-// NodeRef A2NodeRef;
-// NodeRef A3NodeRef;
-// NodeRef A4NodeRef;
-// NodeRef A5NodeRef;
-// NodeRef A6NodeRef;
-// NodeRef A7NodeRef;
-// NodeRef A8NodeRef;
-// NodeRef B9NodeRef;
-// NodeRef B10NodeRef;
-// NodeRef B11NodeRef;
-// NodeRef B12NodeRef;
-// NodeRef B13NodeRef;
-//
-// 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 A1
-// 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);
-// }
-//
-// {
-// // Node A2
-// ChildAssociationRef child = nodeService.createNode(A1NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A2"), ContentModel.TYPE_FOLDER);
-// A2NodeRef = child.getChildRef();
-// nodeService.setProperty(A2NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
-// nodeService.setProperty(A2NodeRef, ContentModel.PROP_NAME, "A2");
-// }
-//
-// {
-// // Node A3
-// ChildAssociationRef child = nodeService.createNode(A1NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A3"), ContentModel.TYPE_CONTENT);
-// A3NodeRef = child.getChildRef();
-// nodeService.setProperty(A3NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
-// 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_FOLDER);
-// A4NodeRef = child.getChildRef();
-// nodeService.setProperty(A4NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
-// nodeService.setProperty(A4NodeRef, ContentModel.PROP_NAME, "A4");
-// }
-// {
-// // 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 A6
-// ChildAssociationRef child = nodeService.createNode(A2NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A6"), ContentModel.TYPE_FOLDER);
-// A6NodeRef = child.getChildRef();
-// nodeService.setProperty(A6NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
-// nodeService.setProperty(A6NodeRef, ContentModel.PROP_NAME, "A6");
-// }
-// {
-// // Node A7
-// ChildAssociationRef child = nodeService.createNode(A4NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A7"), ContentModel.TYPE_CONTENT);
-// A7NodeRef = child.getChildRef();
-// nodeService.setProperty(A7NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
-// nodeService.setProperty(A7NodeRef, ContentModel.PROP_NAME, "A7");
-//
-// ContentWriter writer = contentService.getWriter(A7NodeRef, ContentModel.PROP_CONTENT, true);
-// writer.setLocale(CONTENT_LOCALE);
-// writer.putContent(CONTENT_STRING);
-// }
-// {
-// // Node A8
-// ChildAssociationRef child = nodeService.createNode(A6NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A8"), ContentModel.TYPE_CONTENT);
-// A8NodeRef = child.getChildRef();
-// nodeService.setProperty(A8NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
-// nodeService.setProperty(A8NodeRef, ContentModel.PROP_NAME, "A8");
-//
-// ContentWriter writer = contentService.getWriter(A8NodeRef, ContentModel.PROP_CONTENT, true);
-// writer.setLocale(CONTENT_LOCALE);
-// writer.putContent(CONTENT_STRING);
-// }
-//
-// // Create the transfer target if it does not already exist
-// if(!transferService.targetExists(targetName))
-// {
-// transferMe = createTransferTarget(targetName);
-// } else
-// {
-// transferMe = transferService.getTransferTarget(targetName);
-// }
-// }
-// finally
-// {
-// endTransaction();
-// }
-//
-//
-// /**
-// * Step 1. add A1, A2, A3, A4, A5, A6, A7, A8
-// * transfer(sync)
-// */
-// startNewTransaction();
-// try
-// {
-// /**
-// * Transfer Nodes A1 through A8
-// */
-// {
-// TransferDefinition definition = new TransferDefinition();
-// Setnodes = new HashSet();
-// nodes.add(A1NodeRef);
-// nodes.add(A2NodeRef);
-// nodes.add(A3NodeRef);
-// nodes.add(A4NodeRef);
-// nodes.add(A5NodeRef);
-// nodes.add(A6NodeRef);
-// nodes.add(A7NodeRef);
-// nodes.add(A8NodeRef);
-// 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
-// destNodeRef = testNodeFactory.getMappedNodeRef(A1NodeRef);
-// assertFalse("unit test stuffed up - comparing with self", destNodeRef.equals(transferMe.getNodeRef()));
-// assertTrue("dest node ref does not exist", nodeService.exists(destNodeRef));
-// assertEquals("title is wrong", (String)nodeService.getProperty(destNodeRef, ContentModel.PROP_TITLE), CONTENT_TITLE);
-// assertEquals("type is wrong", nodeService.getType(A1NodeRef), nodeService.getType(destNodeRef));
-//
-// // Check injected transferred aspect.
-// assertNotNull("transferredAspect", (String)nodeService.getProperty(destNodeRef, TransferModel.PROP_REPOSITORY_ID));
-// }
-// finally
-// {
-// endTransaction();
-// }
-//
-// /**
-// * Step 2 add Alien node B9 child of A1(dest). A1(dest) becomes Alien because it contains an alien child.
-// */
-// startNewTransaction();
-// try
-// {
-// destNodeRef = testNodeFactory.getMappedNodeRef(A1NodeRef);
-// ChildAssociationRef child = nodeService.createNode(destNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B9"), ContentModel.TYPE_CONTENT);
-// B9NodeRef = child.getChildRef();
-// nodeService.setProperty(B9NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
-// nodeService.setProperty(B9NodeRef, ContentModel.PROP_NAME, "B9");
-//
-// ContentWriter writer = contentService.getWriter(B9NodeRef, ContentModel.PROP_CONTENT, true);
-// writer.setLocale(CONTENT_LOCALE);
-// writer.putContent(CONTENT_STRING);
-// }
-// finally
-// {
-// endTransaction();
-// }
-//
-// startNewTransaction();
-// try
-// {
-// // Now validate that the target node exists and has similar properties to the source
-// destNodeRef = testNodeFactory.getMappedNodeRef(A1NodeRef);
-// assertFalse("unit test stuffed up - comparing with self", destNodeRef.equals(transferMe.getNodeRef()));
-// assertTrue("dest node ref does not exist", nodeService.exists(destNodeRef));
-// // Check injected transferred aspect.
-// assertTrue("node A1 is not alien", (Boolean)nodeService.getProperty(destNodeRef, TransferModel.PROP_ALIEN));
-// assertNotNull("repository id is null", (String)nodeService.getProperty(destNodeRef, TransferModel.PROP_REPOSITORY_ID));
-// assertNotNull("from repository id is null", (String)nodeService.getProperty(destNodeRef, TransferModel.PROP_FROM_REPOSITORY_ID));
-// }
-// finally
-// {
-// endTransaction();
-// }
-//
-// /**
-// * Step 3 remove alien node B9. A1 becomes non Alien.
-// */
-// startNewTransaction();
-// try
-// {
-// logger.debug("delete node B9");
-// nodeService.deleteNode(B9NodeRef);
-// }
-// finally
-// {
-// endTransaction();
-// }
-//
-// startNewTransaction();
-// try
-// {
-// // Now validate that the target node exists and has similar properties to the source
-// destNodeRef = testNodeFactory.getMappedNodeRef(A1NodeRef);
-// assertFalse("unit test stuffed up - comparing with self", destNodeRef.equals(transferMe.getNodeRef()));
-// assertTrue("dest node ref does not exist", nodeService.exists(destNodeRef));
-//
-// assertFalse("node A1 is still alien", (Boolean)nodeService.getProperty(destNodeRef, TransferModel.PROP_ALIEN));
-// assertNotNull("repository id is null", (String)nodeService.getProperty(destNodeRef, TransferModel.PROP_REPOSITORY_ID));
-// assertNotNull("from repository id is null", (String)nodeService.getProperty(destNodeRef, TransferModel.PROP_FROM_REPOSITORY_ID));
-// }
-// finally
-// {
-// endTransaction();
-// }
-//
-// /**
-// * 4 add Alien node B10 child of A2. A1 and A2 become Alien
-// */
-// startNewTransaction();
-// try
-// {
-// destNodeRef = testNodeFactory.getMappedNodeRef(A2NodeRef);
-// ChildAssociationRef child = nodeService.createNode(destNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B10"), ContentModel.TYPE_CONTENT);
-// B10NodeRef = child.getChildRef();
-// nodeService.setProperty(B10NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
-// nodeService.setProperty(B10NodeRef, ContentModel.PROP_NAME, "B10");
-//
-// ContentWriter writer = contentService.getWriter(B10NodeRef, ContentModel.PROP_CONTENT, true);
-// writer.setLocale(CONTENT_LOCALE);
-// writer.putContent(CONTENT_STRING);
-// }
-// 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);
-//
-// 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));
-// }
-//
-// finally
-// {
-// endTransaction();
-// }
-//
-// /**
-// * 5 remove Alien node B10. A1 and A2 become non Alien
-// */
-// /**
-// * Step 9 remove B12 A6, A2, A1 becomes non Alien.
-// */
-// startNewTransaction();
-// try
-// {
-// nodeService.deleteNode(B10NodeRef);
-// }
-// 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);
-//
-// // BUGBUG
-// //assertFalse("node A1 is still alien", (Boolean)nodeService.getProperty(A1destNodeRef, TransferModel.PROP_ALIEN));
-// //assertFalse("node A2 is still alien", (Boolean)nodeService.getProperty(A2destNodeRef, TransferModel.PROP_ALIEN));
-// }
-//
-// finally
-// {
-// endTransaction();
-// }
-//
-//
-// /**
-// * Step 6
-// * add B12 (child of A6) 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);
-// 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);
-// }
-// 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.getProperty(A1destNodeRef, TransferModel.PROP_ALIEN));
-// assertTrue("node A2 is not alien", (Boolean)nodeService.getProperty(A2destNodeRef, TransferModel.PROP_ALIEN));
-// assertTrue("node A6 is not alien", (Boolean)nodeService.getProperty(A6destNodeRef, TransferModel.PROP_ALIEN));
-// }
-//
-// finally
-// {
-// endTransaction();
-// }
-//
-//
-// /**
-// * Step 7
-// * add B13 A6, A2, A1 remains Alien
-// */
-// startNewTransaction();
-// try
-// {
-// destNodeRef = testNodeFactory.getMappedNodeRef(A6NodeRef);
-// ChildAssociationRef child = nodeService.createNode(destNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B13"), ContentModel.TYPE_CONTENT);
-// B13NodeRef = child.getChildRef();
-// nodeService.setProperty(B13NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
-// nodeService.setProperty(B13NodeRef, ContentModel.PROP_NAME, "B13");
-//
-// ContentWriter writer = contentService.getWriter(B13NodeRef, ContentModel.PROP_CONTENT, true);
-// writer.setLocale(CONTENT_LOCALE);
-// writer.putContent(CONTENT_STRING);
-// }
-// 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.getProperty(A1destNodeRef, TransferModel.PROP_ALIEN));
-// assertTrue("node A2 is not alien", (Boolean)nodeService.getProperty(A2destNodeRef, TransferModel.PROP_ALIEN));
-// assertTrue("node A6 is not alien", (Boolean)nodeService.getProperty(A6destNodeRef, TransferModel.PROP_ALIEN));
-// }
-//
-// finally
-// {
-// endTransaction();
-// }
-//
-// /**
-// * Step 8 remove B13 A6, A2, A1 remains Alien Due to B12
-// */
-// startNewTransaction();
-// try
-// {
-// nodeService.deleteNode(B13NodeRef);
-// }
-// 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.getProperty(A1destNodeRef, TransferModel.PROP_ALIEN));
-// assertTrue("node A2 is not alien", (Boolean)nodeService.getProperty(A2destNodeRef, TransferModel.PROP_ALIEN));
-// assertTrue("node A6 is not alien", (Boolean)nodeService.getProperty(A6destNodeRef, TransferModel.PROP_ALIEN));
-// }
-//
-// finally
-// {
-// endTransaction();
-// }
-//
-//
-// /**
-// * Step 9 remove B12 A6, A2, A1 becomes non Alien.
-// */
-// startNewTransaction();
-// try
-// {
-// nodeService.deleteNode(B12NodeRef);
-// }
-// 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);
-//
-// // BUGBUG
-// //assertFalse("node A1 is still alien", (Boolean)nodeService.getProperty(A1destNodeRef, TransferModel.PROP_ALIEN));
-// //assertFalse("node A2 is still alien", (Boolean)nodeService.getProperty(A2destNodeRef, TransferModel.PROP_ALIEN));
-// //assertFalse("node A6 is still alien", (Boolean)nodeService.getProperty(A6destNodeRef, TransferModel.PROP_ALIEN));
-// }
-//
-// finally
-// {
-// endTransaction();
-// }
-//
-// /**
-// * Step 10 add B9 and B10 A1 and A2 become Alien
-// */
-// startNewTransaction();
-// try
-// {
-// destNodeRef = testNodeFactory.getMappedNodeRef(A1NodeRef);
-// ChildAssociationRef child = nodeService.createNode(destNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B9"), ContentModel.TYPE_CONTENT);
-// B9NodeRef = child.getChildRef();
-// nodeService.setProperty(B9NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
-// nodeService.setProperty(B9NodeRef, ContentModel.PROP_NAME, "B9");
-//
-// ContentWriter writer = contentService.getWriter(B9NodeRef, ContentModel.PROP_CONTENT, true);
-// writer.setLocale(CONTENT_LOCALE);
-// writer.putContent(CONTENT_STRING);
-//
-// destNodeRef = testNodeFactory.getMappedNodeRef(A2NodeRef);
-// child = nodeService.createNode(destNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B10"), ContentModel.TYPE_CONTENT);
-// B10NodeRef = child.getChildRef();
-// nodeService.setProperty(B10NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
-// nodeService.setProperty(B10NodeRef, ContentModel.PROP_NAME, "B10");
-//
-// writer = contentService.getWriter(B10NodeRef, ContentModel.PROP_CONTENT, true);
-// writer.setLocale(CONTENT_LOCALE);
-// writer.putContent(CONTENT_STRING);
-// }
-// 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);
-//
-// 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));
-// }
-// finally
-// {
-// endTransaction();
-// }
-//
-//
-// /**
-// * Step 11 remove B10 A2 becomes non alien A1 remains alien.
-// */
-// startNewTransaction();
-// try
-// {
-// nodeService.deleteNode(B10NodeRef);
-// }
-// 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);
-//
-// // BUGBUG
-// assertTrue("node A1 is still alien", (Boolean)nodeService.getProperty(A1destNodeRef, TransferModel.PROP_ALIEN));
-// //assertFalse("node A2 is still alien", (Boolean)nodeService.getProperty(A2destNodeRef, TransferModel.PROP_ALIEN));
-//
-// }
-//
-// finally
-// {
-// endTransaction();
-// }
-//
-//
-// /**
-// * 12 delete A2 containing alien node B11
-// * transfer sync
-// * (A5, A6, A7 and A8 should be deleted A2 and A4 remain since they contain alien content.)
-// */
-//
-// }
-//
+ /**
+ * Test the transfer method behaviour with respect to sync with (local) alien nodes.
+ *
+ * So we have Repository A transferring content and Repository B is the local repo that we
+ * add and delete alien nodes.
+ *
+ * In general an alien node will prevent deletion of the parent folders
+ *
+ *
+ * Tree of nodes
+ *
+ * A1
+ * | | |
+ * 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
+ *
+ * Test steps -
+ *
+ * - add A1, A2, A3, A4, A5, A6, A7, A8
+ * transfer(sync)
+ * - add Alien node B9. A1 becomes Alien.
+ * - remove alien node B9. A1 becomes non Alien.
+ * - add Alien node B10. A1 and A2 become Alien
+ * - remove Alien node B10. A1 and A2 become non Alien
+ * - add B12 A6, A2, A1 becomes Alien
+ * - add B13 A6, A2, A1 remains Alien
+ * - remove B13 A6, A2, A1 remains Alien
+ * - remove B12 A6, A2, A1 becomes non Alien.
+ * - add B9 and B10 A1 and A2 become Alien
+ * - remove B10 A2 becomes non alien A1 remains alien.
+ * - Add B11, delete A2
+ * 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
+ {
+ setDefaultRollback(false);
+
+ String CONTENT_TITLE = "ContentTitle";
+ String CONTENT_TITLE_UPDATED = "ContentTitleUpdated";
+ Locale CONTENT_LOCALE = Locale.JAPAN;
+ 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.
+ *
+ * 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();
+ // 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)));
+
+ final String localRepositoryId = descriptorService.getCurrentRepositoryDescriptor().getId();
+
+ DescriptorService mockedDescriptorService = getMockDescriptorService(REPO_ID_A);
+ transferServiceImpl.setDescriptorService(mockedDescriptorService);
+
+ /**
+ * Now go ahead and create our first transfer target
+ */
+ String targetName = "testSyncWithAlienNodes";
+ TransferTarget transferMe;
+
+ NodeRef A1NodeRef;
+ NodeRef A2NodeRef;
+ NodeRef A3NodeRef;
+ NodeRef A4NodeRef;
+ NodeRef A5NodeRef;
+ NodeRef A6NodeRef;
+ NodeRef A7NodeRef;
+ NodeRef A8NodeRef;
+ NodeRef B9NodeRef;
+ NodeRef B10NodeRef;
+ NodeRef B11NodeRef;
+ NodeRef B12NodeRef;
+ NodeRef B13NodeRef;
+
+ 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 A1
+ 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);
+ }
+
+ {
+ // Node A2
+ ChildAssociationRef child = nodeService.createNode(A1NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A2"), ContentModel.TYPE_FOLDER);
+ A2NodeRef = child.getChildRef();
+ nodeService.setProperty(A2NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
+ nodeService.setProperty(A2NodeRef, ContentModel.PROP_NAME, "A2");
+ }
+
+ {
+ // Node A3
+ ChildAssociationRef child = nodeService.createNode(A1NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A3"), ContentModel.TYPE_CONTENT);
+ A3NodeRef = child.getChildRef();
+ nodeService.setProperty(A3NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
+ 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_FOLDER);
+ A4NodeRef = child.getChildRef();
+ nodeService.setProperty(A4NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
+ nodeService.setProperty(A4NodeRef, ContentModel.PROP_NAME, "A4");
+ }
+ {
+ // 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 A6
+ ChildAssociationRef child = nodeService.createNode(A2NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A6"), ContentModel.TYPE_FOLDER);
+ A6NodeRef = child.getChildRef();
+ nodeService.setProperty(A6NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
+ nodeService.setProperty(A6NodeRef, ContentModel.PROP_NAME, "A6");
+ }
+ {
+ // Node A7
+ ChildAssociationRef child = nodeService.createNode(A4NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A7"), ContentModel.TYPE_CONTENT);
+ A7NodeRef = child.getChildRef();
+ nodeService.setProperty(A7NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
+ nodeService.setProperty(A7NodeRef, ContentModel.PROP_NAME, "A7");
+
+ ContentWriter writer = contentService.getWriter(A7NodeRef, ContentModel.PROP_CONTENT, true);
+ writer.setLocale(CONTENT_LOCALE);
+ writer.putContent(CONTENT_STRING);
+ }
+ {
+ // Node A8
+ ChildAssociationRef child = nodeService.createNode(A6NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A8"), ContentModel.TYPE_CONTENT);
+ A8NodeRef = child.getChildRef();
+ nodeService.setProperty(A8NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
+ nodeService.setProperty(A8NodeRef, ContentModel.PROP_NAME, "A8");
+
+ ContentWriter writer = contentService.getWriter(A8NodeRef, ContentModel.PROP_CONTENT, true);
+ writer.setLocale(CONTENT_LOCALE);
+ writer.putContent(CONTENT_STRING);
+ }
+
+ // Create the transfer target if it does not already exist
+ if(!transferService.targetExists(targetName))
+ {
+ transferMe = createTransferTarget(targetName);
+ } else
+ {
+ transferMe = transferService.getTransferTarget(targetName);
+ }
+ }
+ finally
+ {
+ endTransaction();
+ }
+
+
+ /**
+ * Step 1. add A1, A2, A3, A4, A5, A6, A7, A8
+ * transfer(sync)
+ */
+ startNewTransaction();
+ try
+ {
+ /**
+ * Transfer Nodes A1 through A8
+ */
+ {
+ TransferDefinition definition = new TransferDefinition();
+ Setnodes = new HashSet();
+ nodes.add(A1NodeRef);
+ nodes.add(A2NodeRef);
+ nodes.add(A3NodeRef);
+ nodes.add(A4NodeRef);
+ nodes.add(A5NodeRef);
+ nodes.add(A6NodeRef);
+ nodes.add(A7NodeRef);
+ nodes.add(A8NodeRef);
+ 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);
+ assertFalse("unit test stuffed up - comparing with self", A1destNodeRef.equals(transferMe.getNodeRef()));
+ assertTrue("dest node ref does not exist", nodeService.exists(A1destNodeRef));
+ assertEquals("title is wrong", (String)nodeService.getProperty(A1destNodeRef, ContentModel.PROP_TITLE), CONTENT_TITLE);
+ assertEquals("type is wrong", nodeService.getType(A1NodeRef), nodeService.getType(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 B9 child of A1(dest). A1(dest) becomes Alien because it contains an alien child.
+ */
+ startNewTransaction();
+ try
+ {
+ destNodeRef = testNodeFactory.getMappedNodeRef(A1NodeRef);
+ ChildAssociationRef child = nodeService.createNode(destNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B9"), ContentModel.TYPE_CONTENT);
+ B9NodeRef = child.getChildRef();
+ nodeService.setProperty(B9NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
+ nodeService.setProperty(B9NodeRef, ContentModel.PROP_NAME, "B9");
+
+ ContentWriter writer = contentService.getWriter(B9NodeRef, ContentModel.PROP_CONTENT, true);
+ writer.setLocale(CONTENT_LOCALE);
+ writer.putContent(CONTENT_STRING);
+ }
+ 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 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));
+ assertTrue("node B9 is not alien", (Boolean)nodeService.hasAspect(B9NodeRef, TransferModel.ASPECT_ALIEN));
+
+ // Temp code
+ List invaders = (List) nodeService.getProperty(A1destNodeRef, TransferModel.PROP_INVADED_BY);
+ assertTrue("invaders contains local repository Id", invaders.contains(localRepositoryId));
+ assertFalse("invaders contains REPO_ID_A", invaders.contains(REPO_ID_A));
+ logger.debug("MER WOZ ERE" + invaders);
+
+ }
+ finally
+ {
+ endTransaction();
+ }
+
+ /**
+ * Step 3 remove alien node B9. A1 becomes non Alien.
+ */
+ startNewTransaction();
+ try
+ {
+ logger.debug("delete node B9");
+ nodeService.deleteNode(B9NodeRef);
+ }
+ finally
+ {
+ endTransaction();
+ }
+
+ startNewTransaction();
+ try
+ {
+ 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));
+ 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();
+ }
+
+ /**
+ * 4 add Alien node B10 child of A2. A1 and A2 become Alien
+ */
+ startNewTransaction();
+ try
+ {
+ destNodeRef = testNodeFactory.getMappedNodeRef(A2NodeRef);
+ ChildAssociationRef child = nodeService.createNode(destNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B10"), ContentModel.TYPE_CONTENT);
+ B10NodeRef = child.getChildRef();
+ nodeService.setProperty(B10NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
+ nodeService.setProperty(B10NodeRef, ContentModel.PROP_NAME, "B10");
+
+ ContentWriter writer = contentService.getWriter(B10NodeRef, ContentModel.PROP_CONTENT, true);
+ writer.setLocale(CONTENT_LOCALE);
+ writer.putContent(CONTENT_STRING);
+ }
+ 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);
+
+ 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));
+ }
+
+ finally
+ {
+ endTransaction();
+ }
+
+ /**
+ * 5 remove Alien node B10. A1 and A2 become non Alien
+ */
+ startNewTransaction();
+ try
+ {
+ logger.debug("delete node B10");
+ nodeService.deleteNode(B10NodeRef);
+ }
+ 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);
+
+ assertFalse("node A1 is still alien aspect", (Boolean)nodeService.hasAspect(A1destNodeRef, TransferModel.ASPECT_ALIEN));
+ assertFalse("node A2 is still alien aspect", (Boolean)nodeService.hasAspect(A2destNodeRef, TransferModel.ASPECT_ALIEN));
+ }
+
+ finally
+ {
+ endTransaction();
+ }
+
+ /**
+ * Step 6
+ * add B12 (child of A6) 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);
+ 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);
+ }
+ 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));
+ }
+
+ finally
+ {
+ endTransaction();
+ }
+
+ /**
+ * Step 7
+ * add B13 A6, A2, A1 remains Alien
+ */
+ startNewTransaction();
+ try
+ {
+ destNodeRef = testNodeFactory.getMappedNodeRef(A6NodeRef);
+ ChildAssociationRef child = nodeService.createNode(destNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B13"), ContentModel.TYPE_CONTENT);
+ B13NodeRef = child.getChildRef();
+ nodeService.setProperty(B13NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
+ nodeService.setProperty(B13NodeRef, ContentModel.PROP_NAME, "B13");
+
+ ContentWriter writer = contentService.getWriter(B13NodeRef, ContentModel.PROP_CONTENT, true);
+ writer.setLocale(CONTENT_LOCALE);
+ writer.putContent(CONTENT_STRING);
+ }
+ 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));
+ }
+
+ finally
+ {
+ endTransaction();
+ }
+
+ /**
+ * Step 8 remove B13 A6, A2, A1 remains Alien Due to B12
+ */
+ startNewTransaction();
+ try
+ {
+ nodeService.deleteNode(B13NodeRef);
+ }
+ 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));
+ }
+
+ finally
+ {
+ endTransaction();
+ }
+
+ /**
+ * Step 9 remove B12 A6, A2, A1 becomes non Alien.
+ */
+ startNewTransaction();
+ try
+ {
+ nodeService.deleteNode(B12NodeRef);
+ }
+ 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);
+
+ assertFalse("node A1 is still alien", (Boolean)nodeService.hasAspect(A1destNodeRef, TransferModel.ASPECT_ALIEN));
+ assertFalse("node A2 is still alien", (Boolean)nodeService.hasAspect(A2destNodeRef, TransferModel.ASPECT_ALIEN));
+ assertFalse("node A6 is still alien", (Boolean)nodeService.hasAspect(A6destNodeRef, TransferModel.ASPECT_ALIEN));
+ }
+
+ finally
+ {
+ endTransaction();
+ }
+
+ /**
+ * Step 10 add B9 and B10 A1 and A2 become Alien
+ */
+ startNewTransaction();
+ try
+ {
+ destNodeRef = testNodeFactory.getMappedNodeRef(A1NodeRef);
+ ChildAssociationRef child = nodeService.createNode(destNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B9"), ContentModel.TYPE_CONTENT);
+ B9NodeRef = child.getChildRef();
+ nodeService.setProperty(B9NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
+ nodeService.setProperty(B9NodeRef, ContentModel.PROP_NAME, "B9");
+
+ ContentWriter writer = contentService.getWriter(B9NodeRef, ContentModel.PROP_CONTENT, true);
+ writer.setLocale(CONTENT_LOCALE);
+ writer.putContent(CONTENT_STRING);
+
+ destNodeRef = testNodeFactory.getMappedNodeRef(A2NodeRef);
+ child = nodeService.createNode(destNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B10"), ContentModel.TYPE_CONTENT);
+ B10NodeRef = child.getChildRef();
+ nodeService.setProperty(B10NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
+ nodeService.setProperty(B10NodeRef, ContentModel.PROP_NAME, "B10");
+
+ writer = contentService.getWriter(B10NodeRef, ContentModel.PROP_CONTENT, true);
+ writer.setLocale(CONTENT_LOCALE);
+ writer.putContent(CONTENT_STRING);
+ }
+ 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);
+
+ 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));
+ }
+ finally
+ {
+ endTransaction();
+ }
+
+
+ /**
+ * Step 11 remove B10 A2 becomes non alien A1 remains alien.
+ */
+ startNewTransaction();
+ try
+ {
+ nodeService.deleteNode(B10NodeRef);
+ }
+ 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);
+
+ // BUGBUG
+ assertTrue("node A1 is still alien", (Boolean)nodeService.hasAspect(A1destNodeRef, TransferModel.ASPECT_ALIEN));
+ assertFalse("node A2 is still alien", (Boolean)nodeService.hasAspect(A2destNodeRef, TransferModel.ASPECT_ALIEN));
+ }
+
+ finally
+ {
+ endTransaction();
+ }
+
+
+ /**
+ * 12 Add Alien node B11.
+ * delete A2 (will cascade delete A4, A5, A6, A7, A8
+ * transfer sync
+ * (A5, A6, A7, A8 and should be deleted A2 and A4 remain since they contain alien content.)
+ */
+ logger.debug("Step 12 Add Node B11, Delete A2 and sync");
+ startNewTransaction();
+ try
+ {
+ destNodeRef = testNodeFactory.getMappedNodeRef(A4NodeRef);
+ ChildAssociationRef child = nodeService.createNode(destNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("B11"), ContentModel.TYPE_CONTENT);
+ B11NodeRef = child.getChildRef();
+ nodeService.setProperty(B11NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
+ nodeService.setProperty(B11NodeRef, ContentModel.PROP_NAME, "B11");
+
+ ContentWriter writer = contentService.getWriter(B11NodeRef, ContentModel.PROP_CONTENT, true);
+ writer.setLocale(CONTENT_LOCALE);
+ writer.putContent(CONTENT_STRING);
+
+ nodeService.deleteNode(A2NodeRef);
+ }
+ finally
+ {
+ endTransaction();
+ }
+
+ startNewTransaction();
+ try
+ {
+ // Now validate A1, A2 and A4 are alien
+ NodeRef A1destNodeRef = testNodeFactory.getMappedNodeRef(A1NodeRef);
+ NodeRef A2destNodeRef = testNodeFactory.getMappedNodeRef(A2NodeRef);
+ NodeRef A4destNodeRef = testNodeFactory.getMappedNodeRef(A4NodeRef);
+
+
+ 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 A4 is not alien", (Boolean)nodeService.hasAspect(A4destNodeRef, TransferModel.ASPECT_ALIEN));
+
+ assertFalse("test error: node A2 not deleted", nodeService.exists(A2NodeRef));
+ assertFalse("test error: node A4 not deleted", nodeService.exists(A4NodeRef));
+ assertFalse("test error: node A5 not deleted", nodeService.exists(A5NodeRef));
+ assertFalse("test error: node A6 not deleted", nodeService.exists(A6NodeRef));
+ assertFalse("test error: node A7 not deleted", nodeService.exists(A7NodeRef));
+ assertFalse("test error: node A8 not deleted", nodeService.exists(A8NodeRef));
+
+ /**
+ * Transfer Nodes A1 through A8
+ */
+ {
+ TransferDefinition definition = new TransferDefinition();
+ Setnodes = new HashSet();
+ nodes.add(A1NodeRef);
+ nodes.add(A3NodeRef);
+ 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);
+ NodeRef A2destNodeRef = testNodeFactory.getMappedNodeRef(A2NodeRef);
+ NodeRef A3destNodeRef = testNodeFactory.getMappedNodeRef(A3NodeRef);
+ NodeRef A4destNodeRef = testNodeFactory.getMappedNodeRef(A4NodeRef);
+ NodeRef A5destNodeRef = testNodeFactory.getMappedNodeRef(A5NodeRef);
+ NodeRef A6destNodeRef = testNodeFactory.getMappedNodeRef(A6NodeRef);
+ NodeRef A7destNodeRef = testNodeFactory.getMappedNodeRef(A7NodeRef);
+ NodeRef A8destNodeRef = testNodeFactory.getMappedNodeRef(A8NodeRef);
+
+ assertTrue("node A1 not alien", (Boolean)nodeService.hasAspect(A1destNodeRef, TransferModel.ASPECT_ALIEN));
+ assertTrue("node A2 not alien", (Boolean)nodeService.hasAspect(A2destNodeRef, TransferModel.ASPECT_ALIEN));
+ assertTrue("node A4 not alien", (Boolean)nodeService.hasAspect(A4destNodeRef, TransferModel.ASPECT_ALIEN));
+ assertTrue("node B11 does not exist", nodeService.exists(B11NodeRef));
+
+ assertTrue("node A3 deleted", nodeService.exists(A3destNodeRef));
+
+ assertFalse("node A5 not deleted", nodeService.exists(A5destNodeRef));
+ assertFalse("node A6 not deleted", nodeService.exists(A6destNodeRef));
+ assertFalse("node A7 not deleted", nodeService.exists(A7destNodeRef));
+ assertFalse("node A8 not deleted", nodeService.exists(A8destNodeRef));
+ }
+
+ finally
+ {
+ endTransaction();
+ }
+ }
+
/**
* Test the transfer method with regard to permissions on a node.
- *
+ *
* Step 1:
* Create a node with a single permission
* Inherit:false
* Read, Admin, Allow
* Transfer
- *
+ *
* Step 2:
* Update it to have several permissions
* Inherit:false
* Read, Everyone, DENY
* Read, Admin, Allow
- *
+ *
* Step 3:
* Remove a permission
* Inherit:false
* Read, Admin, Allow
- *
+ *
* Step 4:
* Revert to inherit all permissions
* Inherit:true
- *
+ *
* This is a unit test so it does some shenanigans to send to the same instance of alfresco.
*/
public void testTransferWithPermissions() throws Exception
@@ -3349,7 +3498,10 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
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);
+
/**
* Now go ahead and create our transfer target
*/
@@ -3712,7 +3864,10 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
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);
+
TransferTarget transferMe;
startNewTransaction();
@@ -4062,15 +4217,12 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
* id and the from repository id
* b) to support hub and spoke - when syncing don't imply delete nodes that are not "from" the transferring system
*
- *
- * Q. What about non sync transfer? Assume that this will update.
- *
* * Tree of nodes
* A1
* | |
* A2 A3 (Content Node) B6 (Content Node)
* |
- * A4 A5 A7
+ * A4 A5 B7
*
* Step 1
* Hub and Spoke Sync
@@ -4099,12 +4251,8 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
* //Update A5
* //Transfer A5 (normal) - should update
*/
- public void testMultiRepoSync() throws Exception
+ public void testTwoRepoSync() throws Exception
{
-
- Descriptor descriptor = descriptorService.getCurrentRepositoryDescriptor();
- String repositoryId = descriptor.getId();
-
/**
* Step 1
* create Tree A1...A6
@@ -4120,8 +4268,6 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
Locale CONTENT_LOCALE = Locale.GERMAN;
String CONTENT_STRING = "Hello";
- String REPO_ID_B = "RepoB";
-
/**
* For unit test
* - replace the HTTP transport with the in-process transport
@@ -4134,7 +4280,12 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
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
*/
@@ -4276,10 +4427,15 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
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, "B4");
- nodeService.setProperty(B6NodeRef, TransferModel.PROP_ALIEN, Boolean.FALSE);
- nodeService.setProperty(B6NodeRef, TransferModel.PROP_FROM_REPOSITORY_ID, REPO_ID_B);
- nodeService.setProperty(B6NodeRef, TransferModel.PROP_REPOSITORY_ID, REPO_ID_B);
+ 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);
@@ -4309,6 +4465,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
{
// 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));
}
finally
{
@@ -4342,7 +4499,9 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
nodeService.setProperty(A3NodeRef, TransferModel.PROP_FROM_REPOSITORY_ID, REPO_ID_B);
nodeService.setProperty(A3NodeRef, TransferModel.PROP_REPOSITORY_ID, REPO_ID_B);
- // Fake Node A7
+ /**
+ * 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);
@@ -4395,8 +4554,342 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
{
endTransaction();
}
- }
+ } // test two repo sync
+ /**
+ * Transfer sync from multiple repos.
+ *
+ * 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
+ * |
+ * A2
+ *
+ * B
+ * |
+ * images
+ * |
+ * B2
+ *
+ * C1
+ * |
+ * images
+ * |
+ * C2
+ *
+ *
+ */
+ public void testMultiRepoSync() 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";
+ TransferTarget transferMe;
+ NodeRef A1NodeRef;
+ NodeRef A2NodeRef;
+ NodeRef A3NodeRef;
+ NodeRef A4NodeRef;
+ NodeRef A5NodeRef;
+ NodeRef B6NodeRef;
+ NodeRef A7NodeRef;
+
+ 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 A5 that we will read and write
+ */
+ {
+ // Node A1
+ 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);
+ }
+
+ {
+ // Node A2
+ ChildAssociationRef child = nodeService.createNode(A1NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A2"), ContentModel.TYPE_FOLDER);
+ A2NodeRef = child.getChildRef();
+ nodeService.setProperty(A2NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
+ nodeService.setProperty(A2NodeRef, ContentModel.PROP_NAME, "A2");
+ }
+
+ {
+ // Node A3
+ ChildAssociationRef child = nodeService.createNode(A1NodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A3"), ContentModel.TYPE_CONTENT);
+ A3NodeRef = child.getChildRef();
+ nodeService.setProperty(A3NodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
+ 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 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);
+ }
+
+ // Create the transfer target if it does not already exist
+ if(!transferService.targetExists(targetName))
+ {
+ transferMe = createTransferTarget(targetName);
+ }
+ else
+ {
+ transferMe = transferService.getTransferTarget(targetName);
+ }
+ }
+ finally
+ {
+ 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();
+ }
+
+ startNewTransaction();
+ try
+ {
+ TransferDefinition definition = new TransferDefinition();
+ definition.setNodes(nodes);
+ definition.setSync(true);
+ transferService.transfer(targetName, definition);
+ }
+ finally
+ {
+ endTransaction();
+ }
+
+ 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));
+ }
+ 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);
+
+ startNewTransaction();
+ try
+ {
+ TransferDefinition definition = new TransferDefinition();
+ definition.setNodes(nodes);
+ definition.setSync(true);
+ transferService.transfer(targetName, definition);
+ }
+ finally
+ {
+ endTransaction();
+ }
+
+ try
+ {
+ assertTrue("dest node A7 does not exist", nodeService.exists(testNodeFactory.getMappedNodeRef(A7NodeRef)));
+
+ 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);
+ }
+ finally
+ {
+ endTransaction();
+ }
+ } // test multi repo sync
+
+
+
// Utility methods below.
private TransferTarget createTransferTarget(String name)
{
@@ -4416,7 +4909,15 @@ 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);
+// }
private void createUser(String userName, String password)
{
@@ -4434,4 +4935,15 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
this.personService.createPerson(ppOne);
}
}
+
+ private DescriptorService getMockDescriptorService(String repositoryId)
+ {
+ DescriptorService descriptorService = mock(DescriptorService.class);
+ Descriptor descriptor = mock(Descriptor.class);
+
+ when(descriptor.getId()).thenReturn(repositoryId);
+ when(descriptorService.getCurrentRepositoryDescriptor()).thenReturn(descriptor);
+
+ return descriptorService;
+ }
}