diff --git a/config/alfresco/transfer-service-context.xml b/config/alfresco/transfer-service-context.xml
index f3df681afb..a098c5c51b 100644
--- a/config/alfresco/transfer-service-context.xml
+++ b/config/alfresco/transfer-service-context.xml
@@ -153,6 +153,8 @@
+
+
> orphans = new HashMap>(89);
+
+ /**
+ * node ref mapping from source to destination categories
+ */
+ private Map categoryMap = new HashMap();
/**
* @param transferId
@@ -277,6 +294,8 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
// First, create a shallow copy of the supplied property map...
Map props = new HashMap(node.getProperties());
+ processCategories(props, node.getManifestCategories());
+
injectTransferred(props);
// Split out the content properties and sanitise the others
@@ -532,6 +551,8 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
Map props = new HashMap(node.getProperties());
Map existingProps = nodeService.getProperties(nodeToUpdate);
+ processCategories(props, node.getManifestCategories());
+
// inject transferred properties/aspect here
injectTransferred(props);
@@ -966,6 +987,181 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
{
return permissionService;
}
+
+ /**
+ * Process categories.
+ *
+ * CRUD of Categories and Tags - also maps noderefs of type d:content from source to target
+ *
+ *
+ * @param properties
+ * @param manifestCategories
+ */
+ private void processCategories(Map properties, Map manifestCategories)
+ {
+ if(manifestCategories != null)
+ {
+ for(Map.Entry val : properties.entrySet())
+ {
+ PropertyDefinition def = dictionaryService.getProperty(val.getKey());
+ if(def != null)
+ {
+ if(def.getDataType().getName().isMatch(DataTypeDefinition.CATEGORY))
+ {
+ Serializable thing = val.getValue();
+ if(thing != null)
+ {
+ if(def.isMultiValued())
+ {
+ if(thing instanceof java.util.Collection)
+ {
+ List newCategories = new ArrayList();
+ java.util.Collection c = (java.util.Collection)thing;
+ for(NodeRef sourceCategoryNodeRef : c)
+ {
+ if(log.isDebugEnabled())
+ {
+ log.debug("sourceCategoryNodeRef" + sourceCategoryNodeRef);
+ }
+ // substitute target node ref fot source node ref
+ NodeRef targetNodeRef = processCategory(sourceCategoryNodeRef, manifestCategories);
+ newCategories.add(targetNodeRef);
+ }
+ // substitute target node refs for source node refs
+ properties.put(val.getKey(), (Serializable)newCategories);
+ }
+ else
+ {
+ throw new AlfrescoRuntimeException("Multi valued object is not a collection" + val.getKey() );
+ }
+ }
+ else
+ {
+ NodeRef sourceCategoryNodeRef = (NodeRef)thing;
+ if(log.isDebugEnabled())
+ {
+ log.debug("sourceCategoryNodeRef:" + sourceCategoryNodeRef);
+ }
+ NodeRef targetNodeRef = processCategory(sourceCategoryNodeRef, manifestCategories);
+ // substitute target node ref for source node ref
+ properties.put(val.getKey(), targetNodeRef);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * process category - maps the category node ref from the source system to the target system.
+ *
+ * It will lazily create any missing categories and tags as it executes.
+ *
+ * @param sourceCategoryNodeRef
+ * @param manifestCategories
+ * @return targetNodeRef
+ */
+ private NodeRef processCategory(final NodeRef sourceCategoryNodeRef, final Map manifestCategories)
+ {
+
+ // first check cache to see whether we have already mapped this category
+ NodeRef destinationNodeRef = categoryMap.get(sourceCategoryNodeRef);
+ if(destinationNodeRef != null)
+ {
+ return destinationNodeRef;
+ }
+
+ // No we havn't seen this category before, have we got the details in the manifest
+ ManifestCategory category = manifestCategories.get(sourceCategoryNodeRef);
+ if(category != null)
+ {
+ final String path = category.getPath();
+ final Path catPath = PathHelper.stringToPath(path);
+
+ final Path.Element aspectName = catPath.get(2);
+ final QName aspectQName = QName.createQName(aspectName.getElementString());
+
+ if(aspectQName.equals(ContentModel.ASPECT_TAGGABLE))
+ {
+ Path.Element tagName = catPath.get(3);
+ // Category is a tag
+ QName tagQName = QName.createQName(tagName.getElementString());
+ destinationNodeRef = taggingService.getTagNodeRef(sourceCategoryNodeRef.getStoreRef(), tagQName.getLocalName());
+ if(destinationNodeRef != null)
+ {
+ log.debug("found existing tag" + tagQName.getLocalName());
+ categoryMap.put(sourceCategoryNodeRef, destinationNodeRef);
+ return destinationNodeRef;
+ }
+ destinationNodeRef = taggingService.createTag(sourceCategoryNodeRef.getStoreRef(), tagQName.getLocalName());
+ if(destinationNodeRef != null)
+ {
+ log.debug("created new tag" + tagQName.getLocalName());
+ categoryMap.put(sourceCategoryNodeRef, destinationNodeRef);
+ return destinationNodeRef;
+ }
+ }
+ else
+ {
+ // Categories are finniky about permissions, so run as system
+ RunAsWork processCategory = new RunAsWork()
+ {
+ @Override
+ public NodeRef doWork() throws Exception
+ {
+ QName rootCatName = QName.createQName(catPath.get(3).getElementString());
+
+ Collection roots = categoryService.getRootCategories(sourceCategoryNodeRef.getStoreRef(), aspectQName);
+
+ /**
+ * Get the root category node ref
+ */
+ NodeRef rootCategoryNodeRef = null;
+ for(ChildAssociationRef ref : roots)
+ {
+ if(ref.getQName().equals(rootCatName))
+ {
+ rootCategoryNodeRef = ref.getChildRef();
+ break;
+ }
+ }
+
+ if(rootCategoryNodeRef == null)
+ {
+ // Root category does not exist
+ rootCategoryNodeRef = categoryService.createRootCategory(sourceCategoryNodeRef.getStoreRef(), aspectQName, rootCatName.getLocalName());
+ }
+
+ NodeRef workingNodeRef = rootCategoryNodeRef;
+ // Root category does already exist - step through any sub-categories
+ for(int i = 4; i < catPath.size(); i++)
+ {
+ Path.Element element = catPath.get(i);
+ QName subCatName = QName.createQName(element.toString());
+ ChildAssociationRef child = categoryService.getCategory(workingNodeRef, aspectQName, subCatName.getLocalName());
+ if(child != null)
+ {
+ workingNodeRef = child.getChildRef();
+ }
+ else
+ {
+ workingNodeRef = categoryService.createCategory(workingNodeRef, subCatName.getLocalName());
+ }
+ }
+ return workingNodeRef;
+ }
+
+ };
+ destinationNodeRef = AuthenticationUtil.runAs(processCategory, AuthenticationUtil.SYSTEM_USER_NAME);
+ categoryMap.put(sourceCategoryNodeRef, destinationNodeRef);
+ return destinationNodeRef;
+ }
+ } // if manifest category exists
+
+ return sourceCategoryNodeRef;
+
+ }
/**
* inject transferred
@@ -1010,4 +1206,24 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
return alienProcessor;
}
+ public CategoryService getCategoryService()
+ {
+ return categoryService;
+ }
+
+ public void setCategoryService(CategoryService categoryService)
+ {
+ this.categoryService = categoryService;
+ }
+
+ public TaggingService getTaggingService()
+ {
+ return taggingService;
+ }
+
+ public void setTaggingService(TaggingService taggingService)
+ {
+ this.taggingService = taggingService;
+ }
+
}
diff --git a/source/java/org/alfresco/repo/transfer/TransferServiceImpl2.java b/source/java/org/alfresco/repo/transfer/TransferServiceImpl2.java
index 30f290efca..d25dee7bdd 100644
--- a/source/java/org/alfresco/repo/transfer/TransferServiceImpl2.java
+++ b/source/java/org/alfresco/repo/transfer/TransferServiceImpl2.java
@@ -576,6 +576,8 @@ public class TransferServiceImpl2 implements TransferService2
}
};
eventProcessor.addObserver(reportCallback);
+
+ TransferContext transferContext = new TransferContext();
// start transfer
ClientTransferState clientState = ClientTransferState.Begin;
@@ -589,7 +591,7 @@ public class TransferServiceImpl2 implements TransferService2
{
eventProcessor.start();
- manifest = createManifest(definition, localRepositoryId, fromVersion);
+ manifest = createManifest(definition, localRepositoryId, fromVersion, transferContext);
logger.debug("transfer begin");
target = getTransferTarget(targetName);
checkTargetEnabled(target);
@@ -919,7 +921,7 @@ public class TransferServiceImpl2 implements TransferService2
}
}
- private File createManifest(TransferDefinition definition, String repositoryId, TransferVersion fromVersion)
+ private File createManifest(TransferDefinition definition, String repositoryId, TransferVersion fromVersion, TransferContext transferContext)
throws IOException, SAXException
{
// which nodes to write to the snapshot
@@ -966,7 +968,7 @@ public class TransferServiceImpl2 implements TransferService2
{
for (NodeRef nodeRef : nodes)
{
- TransferManifestNode node = transferManifestNodeFactory.createTransferManifestNode(nodeRef, definition);
+ TransferManifestNode node = transferManifestNodeFactory.createTransferManifestNode(nodeRef, definition, transferContext);
formatter.writeTransferManifestNode(node);
}
}
@@ -974,7 +976,7 @@ public class TransferServiceImpl2 implements TransferService2
{
for (NodeRef nodeRef : nodesToRemove)
{
- TransferManifestNode node = transferManifestNodeFactory.createTransferManifestNode(nodeRef, definition,
+ TransferManifestNode node = transferManifestNodeFactory.createTransferManifestNode(nodeRef, definition, transferContext,
true);
formatter.writeTransferManifestNode(node);
}
diff --git a/source/java/org/alfresco/repo/transfer/manifest/ManifestModel.java b/source/java/org/alfresco/repo/transfer/manifest/ManifestModel.java
index 3a1c01dca1..b38bf19578 100644
--- a/source/java/org/alfresco/repo/transfer/manifest/ManifestModel.java
+++ b/source/java/org/alfresco/repo/transfer/manifest/ManifestModel.java
@@ -57,6 +57,9 @@ public interface ManifestModel extends TransferModel
static final String LOCALNAME_ELEMENT_CONTENT_HEADER = "content";
static final String LOCALNAME_ELEMENT_ACL = "acl";
static final String LOCALNAME_ELEMENT_ACL_PERMISSION = "permission";
+ static final String LOCALNAME_ELEMENT_CATEGORIES = "categories";
+ static final String LOCALNAME_ELEMENT_CATEGORY = "category";
+
// Manifest file prefix
static final String MANIFEST_PREFIX = "xfer";
diff --git a/source/java/org/alfresco/repo/transfer/manifest/TransferManifestNodeFactory.java b/source/java/org/alfresco/repo/transfer/manifest/TransferManifestNodeFactory.java
index 76895979e4..a5e954aa13 100644
--- a/source/java/org/alfresco/repo/transfer/manifest/TransferManifestNodeFactory.java
+++ b/source/java/org/alfresco/repo/transfer/manifest/TransferManifestNodeFactory.java
@@ -18,6 +18,7 @@
*/
package org.alfresco.repo.transfer.manifest;
+import org.alfresco.repo.transfer.TransferContext;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.transfer.TransferDefinition;
@@ -29,9 +30,10 @@ public interface TransferManifestNodeFactory
* specifying false
as the value of the forceDelete
parameter.
* @param nodeRef The identifier of the node to be distilled for transfer
* @param definition The transfer definition against which the node is being transferred
+ * @param transferContext internal runtime context of a transfer
* @return An object that holds a snapshot of the state of the specified node suitable for transfer elsewhere.
*/
- TransferManifestNode createTransferManifestNode(NodeRef nodeRef, TransferDefinition definition);
+ TransferManifestNode createTransferManifestNode(NodeRef nodeRef, TransferDefinition definition, TransferContext transferContext);
/**
* Create an object that represents the specified node in a form that can be used to transfer it elsewhere
@@ -40,7 +42,8 @@ public interface TransferManifestNodeFactory
* @param forceDelete If this flag is set then the returned TransferManifestNode object will represent the removal
* of the specified node, even if the node still exists in this repository. This allows a node to be removed from the
* target repository even if it hasn't been removed in the source repository.
+ * @param transferContext internal runtime context of a transfer
* @return An object that holds a snapshot of the state of the specified node suitable for transfer elsewhere.
*/
- TransferManifestNode createTransferManifestNode(NodeRef nodeRef, TransferDefinition definition, boolean forceDelete);
+ TransferManifestNode createTransferManifestNode(NodeRef nodeRef, TransferDefinition definition, TransferContext transferContext, boolean forceDelete);
}
diff --git a/source/java/org/alfresco/repo/transfer/manifest/TransferManifestNodeFactoryImpl.java b/source/java/org/alfresco/repo/transfer/manifest/TransferManifestNodeFactoryImpl.java
index 4c20c7e5e7..506508ed5a 100644
--- a/source/java/org/alfresco/repo/transfer/manifest/TransferManifestNodeFactoryImpl.java
+++ b/source/java/org/alfresco/repo/transfer/manifest/TransferManifestNodeFactoryImpl.java
@@ -27,6 +27,8 @@ import java.util.Map;
import java.util.Set;
import org.alfresco.model.ContentModel;
+import org.alfresco.repo.transfer.TransferContext;
+import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
@@ -60,12 +62,12 @@ public class TransferManifestNodeFactoryImpl implements TransferManifestNodeFact
//NOOP
}
- public TransferManifestNode createTransferManifestNode(NodeRef nodeRef, TransferDefinition definition)
+ public TransferManifestNode createTransferManifestNode(NodeRef nodeRef, TransferDefinition definition, TransferContext transferContext)
{
- return createTransferManifestNode(nodeRef, definition, false);
+ return createTransferManifestNode(nodeRef, definition, transferContext, false);
}
- public TransferManifestNode createTransferManifestNode(NodeRef nodeRef, TransferDefinition definition, boolean forceDelete)
+ public TransferManifestNode createTransferManifestNode(NodeRef nodeRef, TransferDefinition definition, TransferContext transferContext, boolean forceDelete)
{
NodeRef.Status status = nodeService.getNodeStatus(nodeRef);
@@ -203,6 +205,57 @@ public class TransferManifestNodeFactoryImpl implements TransferManifestNodeFact
}
}
acl.setPermissions(mps);
+
+ /**
+ * Expand d:category information so we can re-create on target
+ */
+ Map categories = new HashMap();
+
+ Map properties = node.getProperties();
+
+ for(Map.Entry val : properties.entrySet())
+ {
+ PropertyDefinition def = dictionaryService.getProperty(val.getKey());
+ if(def != null)
+ {
+ if(def.getDataType().getName().isMatch(DataTypeDefinition.CATEGORY))
+ {
+ if(def.isMultiValued())
+ {
+ Serializable thing = val.getValue();
+ if(thing instanceof java.util.Collection)
+ {
+ java.util.Collection c = (java.util.Collection)thing;
+ for(NodeRef categoryNodeRef : c)
+ {
+ if(categoryNodeRef != null)
+ {
+ categories.put(categoryNodeRef, getManifestCategory(transferContext, categoryNodeRef));
+ }
+ }
+ }
+ else
+ {
+ NodeRef categoryNodeRef = (NodeRef)val.getValue();
+ if(categoryNodeRef != null)
+ {
+ categories.put(categoryNodeRef, getManifestCategory(transferContext, categoryNodeRef));
+ }
+ }
+ }
+ else
+ {
+ NodeRef categoryNodeRef = (NodeRef)val.getValue();
+ if(categoryNodeRef != null)
+ {
+ categories.put(categoryNodeRef, getManifestCategory(transferContext, categoryNodeRef));
+ }
+ }
+ }
+ }
+ }
+
+ node.setManifestCategories(categories);
return node;
}
@@ -264,6 +317,22 @@ public class TransferManifestNodeFactoryImpl implements TransferManifestNodeFact
return filteredProperties;
}
}
+
+ private ManifestCategory getManifestCategory(TransferContext transferContext, NodeRef categoryNodeRef)
+ {
+ ManifestCategory c = transferContext.getManifestCategoriesCache().get(categoryNodeRef);
+
+ if(c != null)
+ {
+ return c;
+ }
+ c = new ManifestCategory();
+
+ Path p = nodeService.getPath(categoryNodeRef);
+ c.setPath(p.toString());
+ transferContext.getManifestCategoriesCache().put(categoryNodeRef, c);
+ return c;
+ }
public void setNodeService(NodeService nodeService)
{
diff --git a/source/java/org/alfresco/repo/transfer/manifest/TransferManifestNormalNode.java b/source/java/org/alfresco/repo/transfer/manifest/TransferManifestNormalNode.java
index 9c9867c397..3d8acde77e 100644
--- a/source/java/org/alfresco/repo/transfer/manifest/TransferManifestNormalNode.java
+++ b/source/java/org/alfresco/repo/transfer/manifest/TransferManifestNormalNode.java
@@ -51,6 +51,9 @@ public class TransferManifestNormalNode implements TransferManifestNode
private List targetAssocs;
private Path parentPath;
private ManifestAccessControl accessControl;
+
+ // NodeRef is noderef of type d:category ManifestCategory provides the extra meta-data
+ private Map categories;
public void setNodeRef(NodeRef nodeRef)
{
@@ -190,5 +193,15 @@ public class TransferManifestNormalNode implements TransferManifestNode
{
this.ancestorType = ancestorType;
}
-
+
+ public void setManifestCategories(Map categories)
+ {
+ this.categories = categories;
+ }
+
+ public Map getManifestCategories()
+ {
+ return this.categories;
+ }
+
}
diff --git a/source/java/org/alfresco/repo/transfer/manifest/XMLTransferManifestReader.java b/source/java/org/alfresco/repo/transfer/manifest/XMLTransferManifestReader.java
index 0b985a5708..2153d79a1e 100644
--- a/source/java/org/alfresco/repo/transfer/manifest/XMLTransferManifestReader.java
+++ b/source/java/org/alfresco/repo/transfer/manifest/XMLTransferManifestReader.java
@@ -349,6 +349,18 @@ public class XMLTransferManifestReader extends DefaultHandler implements Content
perm.setStatus(status);
props.put("permission", perm);
}
+ else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CATEGORIES))
+ {
+ props.put("categories", new HashMap());
+ }
+ else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CATEGORY))
+ {
+ ManifestCategory cat = new ManifestCategory();
+ String path = (String)atts.getValue("", "path");
+ cat.setPath(path);
+ props.put("category", cat);
+ }
+
} // if transfer URI
} // startElement
@@ -634,6 +646,18 @@ public class XMLTransferManifestReader extends DefaultHandler implements Content
ManifestPermission permission = (ManifestPermission)props.get("permission");
acl.addPermission(permission);
}
+ else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CATEGORIES))
+ {
+ TransferManifestNormalNode node = (TransferManifestNormalNode)props.get("node");
+ Map categories = (Map )props.get("categories");
+ node.setManifestCategories(categories);
+ }
+ else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CATEGORY))
+ {
+ Map categories = (Map )props.get("categories");
+ ManifestCategory category = (ManifestCategory)props.get("category");
+ categories.put(new NodeRef(buffer.toString().trim()),category);
+ }
} // if transfer URI
diff --git a/source/java/org/alfresco/repo/transfer/manifest/XMLTransferManifestWriter.java b/source/java/org/alfresco/repo/transfer/manifest/XMLTransferManifestWriter.java
index aa47b16946..ee0342dcc9 100644
--- a/source/java/org/alfresco/repo/transfer/manifest/XMLTransferManifestWriter.java
+++ b/source/java/org/alfresco/repo/transfer/manifest/XMLTransferManifestWriter.java
@@ -36,6 +36,7 @@ import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.MLText;
+import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.repository.datatype.TypeConversionException;
@@ -281,6 +282,8 @@ public class XMLTransferManifestWriter implements TransferManifestWriter
{
writePrimaryParent(node.getPrimaryParentAssoc(), node.getParentPath());
}
+
+ writeCategories(node.getManifestCategories());
writeAspects(node.getAspects());
@@ -300,6 +303,42 @@ public class XMLTransferManifestWriter implements TransferManifestWriter
ManifestModel.LOCALNAME_ELEMENT_NODE, PREFIX + ":"
+ ManifestModel.LOCALNAME_ELEMENT_NODE);
}
+
+ private void writeCategories(Map categories) throws SAXException
+ {
+ writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI,
+ ManifestModel.LOCALNAME_ELEMENT_PROPERTIES, PREFIX + ":"
+ + ManifestModel.LOCALNAME_ELEMENT_CATEGORIES, EMPTY_ATTRIBUTES);
+ if (categories != null)
+ {
+ for (Entry entry : categories.entrySet())
+ {
+ writeCategory(entry.getKey(), entry.getValue());
+ }
+ }
+
+ writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI,
+ ManifestModel.LOCALNAME_ELEMENT_PROPERTIES, PREFIX + ":"
+ + ManifestModel.LOCALNAME_ELEMENT_CATEGORIES);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void writeCategory (NodeRef nodeRef, ManifestCategory value) throws SAXException
+ {
+
+ AttributesImpl attributes = new AttributesImpl();
+ attributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "path", "path", "String",
+ value.getPath());
+ writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI,
+ ManifestModel.LOCALNAME_ELEMENT_CATEGORY, PREFIX + ":"
+ + ManifestModel.LOCALNAME_ELEMENT_CATEGORY, attributes);
+ writeValue(nodeRef);
+
+ writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI,
+ ManifestModel.LOCALNAME_ELEMENT_CATEGORY, PREFIX + ":"
+ + ManifestModel.LOCALNAME_ELEMENT_CATEGORY);
+ }
+
private void writeProperties(Map properties) throws SAXException
{
diff --git a/source/test-java/org/alfresco/repo/transfer/TransferServiceImplTest.java b/source/test-java/org/alfresco/repo/transfer/TransferServiceImplTest.java
index 072cff450f..26c5eef80e 100644
--- a/source/test-java/org/alfresco/repo/transfer/TransferServiceImplTest.java
+++ b/source/test-java/org/alfresco/repo/transfer/TransferServiceImplTest.java
@@ -69,6 +69,8 @@ import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.StoreRef;
+import org.alfresco.service.cmr.search.CategoryService;
+import org.alfresco.service.cmr.search.CategoryService.Depth;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.ResultSetRow;
import org.alfresco.service.cmr.search.SearchService;
@@ -76,6 +78,7 @@ import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.MutableAuthenticationService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
+import org.alfresco.service.cmr.tagging.TaggingService;
import org.alfresco.service.cmr.transfer.TransferCallback;
import org.alfresco.service.cmr.transfer.TransferDefinition;
import org.alfresco.service.cmr.transfer.TransferEvent;
@@ -125,6 +128,8 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
private DescriptorService descriptorService;
private CopyService copyService;
private Descriptor serverDescriptor;
+ private TaggingService taggingService;
+ private CategoryService categoryService;
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";
@@ -159,6 +164,8 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
this.personService = (PersonService)this.applicationContext.getBean("PersonService");
this.descriptorService = (DescriptorService)this.applicationContext.getBean("DescriptorService");
this.copyService = (CopyService)this.applicationContext.getBean("CopyService");
+ this.taggingService = ((TaggingService)this.applicationContext.getBean("TaggingService"));
+ this.categoryService = (CategoryService)this.applicationContext.getBean("CategoryService");
this.serverDescriptor = descriptorService.getServerDescriptor();
@@ -1886,7 +1893,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
*/
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());
+ assertEquals("unable to find guest home", 1, guestHomeResult.length());
final NodeRef guestHome = guestHomeResult.getNodeRef(0);
final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
@@ -3156,7 +3163,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
nodeService.setProperty(testContext.folderNodeRef, ContentModel.PROP_NAME, name);
// Side effect - initialisee nodeid mapping
- testNodeFactory.createTransferManifestNode(testContext.folderNodeRef, def);
+ testNodeFactory.createTransferManifestNode(testContext.folderNodeRef, def, new TransferContext());
child = nodeService.createNode(testContext.folderNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("source"), ContentModel.TYPE_CONTENT);
testContext.sourceNodeRef = child.getChildRef();
@@ -3164,17 +3171,17 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
nodeService.setProperty(testContext.sourceNodeRef, ContentModel.PROP_NAME, "source");
// Side effect - initialise nodeid mapping
- testNodeFactory.createTransferManifestNode(testContext.sourceNodeRef, def);
+ testNodeFactory.createTransferManifestNode(testContext.sourceNodeRef, def, new TransferContext());
child = nodeService.createNode(testContext.folderNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("target"), ContentModel.TYPE_CONTENT);
testContext.targetNodeRef = child.getChildRef();
nodeService.setProperty(testContext.targetNodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
nodeService.setProperty(testContext.targetNodeRef, ContentModel.PROP_NAME, "target");
- testNodeFactory.createTransferManifestNode(testContext.folderNodeRef, def);
+ testNodeFactory.createTransferManifestNode(testContext.folderNodeRef, def, new TransferContext());
nodeService.createAssociation(testContext.sourceNodeRef, testContext.targetNodeRef, ContentModel.ASSOC_REFERENCES);
// Side effect - initialise nodeid mapping
- testNodeFactory.createTransferManifestNode(testContext.targetNodeRef, def);
+ testNodeFactory.createTransferManifestNode(testContext.targetNodeRef, def, new TransferContext());
/**
* Make sure the transfer target exists and is enabled.
@@ -3378,7 +3385,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
nodeService.setProperty(testContext.rootNodeRef, ContentModel.PROP_NAME, name);
// Side effect - initialisee nodeid mapping
- testNodeFactory.createTransferManifestNode(testContext.rootNodeRef, def);
+ testNodeFactory.createTransferManifestNode(testContext.rootNodeRef, def, new TransferContext());
child = nodeService.createNode(testContext.rootNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A1"), ContentModel.TYPE_FOLDER);
testContext.folderNodeRef = child.getChildRef();
@@ -3386,7 +3393,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
nodeService.setProperty(testContext.folderNodeRef, ContentModel.PROP_NAME, "A1");
// Side effect - initialise nodeid mapping
- testNodeFactory.createTransferManifestNode(testContext.folderNodeRef, def);
+ testNodeFactory.createTransferManifestNode(testContext.folderNodeRef, def, new TransferContext());
child = nodeService.createNode(testContext.folderNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName("A2"), ContentModel.TYPE_CONTENT);
testContext.contentNodeRef = child.getChildRef();
@@ -3394,7 +3401,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
nodeService.setProperty(testContext.contentNodeRef, ContentModel.PROP_NAME, "A2");
// Side effect - initialise nodeid mapping
- testNodeFactory.createTransferManifestNode(testContext.contentNodeRef, def);
+ testNodeFactory.createTransferManifestNode(testContext.contentNodeRef, def, new TransferContext());
// Put nodes into destination
@@ -3465,7 +3472,280 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
tran.doInTransaction(transferCB);
tran.doInTransaction(validateCB);
- } // testExistingNodes
+ } // testExistingNodes
+
+ /**
+ * Test categories and tags (CRUD).
+ *
+ * Step 1: Create a new node with a tag
+ * transfer
+ *
+ * Step 2: Add another tag
+ * transfer
+ *
+ * Step 3: Delete a tag
+ * transfer
+ *
+ * Step 4: Add a category
+ * transfer
+ *
+ * Step 5: Add another category this one deep
+ * transfer
+ *
+ * Step 6: Delete a category
+ * transfer
+ *
+ * This is a unit test so it does some shenanigans to send to the same instance of alfresco.
+ */
+ public void testCategoriesAndTags() throws Exception
+ {
+ final String CONTENT_TITLE = "ContentTitle";
+ final String CONTENT_TITLE_UPDATED = "ContentTitleUpdated";
+ final Locale CONTENT_LOCALE = Locale.GERMAN;
+ final String CONTENT_STRING = "Hello World";
+ final String CONTENT_UPDATE_STRING = "Foo Bar";
+ final String targetName = "testCategoriesAndTags";
+ final String TAG_1_NAME = "tag1";
+ final String TAG_2_NAME = "tag2";
+
+ final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
+
+ class TestContext
+ {
+ TransferTarget transferMe;
+ NodeRef contentNodeRef;
+ NodeRef destNodeRef;
+ };
+
+ /**
+ * Unit test kludge to transfer from guest home to company home
+ */
+ final UnitTestTransferManifestNodeFactory testNodeFactory = unitTestKludgeToTransferGuestHomeToCompanyHome();
+
+ DescriptorService mockedDescriptorService = getMockDescriptorService(REPO_ID_A);
+ transferServiceImpl.setDescriptorService(mockedDescriptorService);
+
+ RetryingTransactionCallback setupCB = new RetryingTransactionCallback()
+ {
+ @Override
+ public TestContext execute() throws Throwable
+ {
+ TestContext ctx = new TestContext();
+
+ /**
+ * 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 node that we will read and write
+ */
+ String name = GUID.generate();
+ ChildAssociationRef child = nodeService.createNode(guestHome, ContentModel.ASSOC_CONTAINS, QName.createQName(name), ContentModel.TYPE_CONTENT);
+ ctx.contentNodeRef = child.getChildRef();
+ nodeService.setProperty(ctx.contentNodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
+ nodeService.setProperty(ctx.contentNodeRef, ContentModel.PROP_NAME, name);
+
+ // Add the TAG to be transferred
+ taggingService.addTag(ctx.contentNodeRef, TAG_1_NAME);
+
+ if(!transferService.targetExists(targetName))
+ {
+ ctx.transferMe = createTransferTarget(targetName);
+ }
+ else
+ {
+ ctx.transferMe = transferService.getTransferTarget(targetName);
+ }
+ transferService.enableTransferTarget(targetName, true);
+
+ return ctx;
+ }
+ };
+ final TestContext testContext = tran.doInTransaction(setupCB);
+
+ /**
+ * Step 1: Transfer our which has a tag
+ */
+ logger.debug("First transfer - create new node with a tag");
+ RetryingTransactionCallback transferCB = new RetryingTransactionCallback() {
+
+ @Override
+ public Void execute() throws Throwable
+ {
+ TransferDefinition definition = new TransferDefinition();
+ Setnodes = new HashSet();
+ nodes.add(testContext.contentNodeRef);
+ definition.setNodes(nodes);
+ transferService.transfer(targetName, definition);
+ return null;
+ }
+ };
+ tran.doInTransaction(transferCB);
+
+ RetryingTransactionCallback validateStep1CB = new RetryingTransactionCallback() {
+
+ @Override
+ public Void execute() throws Throwable
+ {
+ // Now validate that the target node exists and has similar properties to the source
+ testContext.destNodeRef = testNodeFactory.getMappedNodeRef( testContext.contentNodeRef);
+ assertFalse("unit test stuffed up - comparing with self", testContext.destNodeRef.equals( testContext.transferMe.getNodeRef()));
+ assertTrue("dest node ref does not exist", nodeService.exists( testContext.destNodeRef));
+ assertEquals("title is wrong", (String)nodeService.getProperty( testContext.destNodeRef, ContentModel.PROP_TITLE), CONTENT_TITLE);
+ assertEquals("type is wrong", nodeService.getType( testContext.contentNodeRef), nodeService.getType( testContext.destNodeRef));
+
+ List tags = taggingService.getTags(testContext.contentNodeRef);
+ assertNotNull(tags);
+ assertTrue(tags.size() == 1);
+ assertTrue(tags.contains(TAG_1_NAME));
+
+ // Now add another tag for step number 2
+ taggingService.addTag(testContext.contentNodeRef, TAG_2_NAME);
+ return null;
+
+ }
+ };
+ tran.doInTransaction(validateStep1CB);
+
+ /**
+ * Step 2:
+ * Transfer our node again - With another tag
+ */
+ logger.debug("Second transfer - add a second tag");
+ tran.doInTransaction(transferCB);
+
+ RetryingTransactionCallback validateStep2CB = new RetryingTransactionCallback() {
+
+ @Override
+ public Void execute() throws Throwable
+ {
+
+ // Now validate that the target node exists and has similar properties to the source
+ assertFalse("unit test stuffed up - comparing with self", testContext.destNodeRef.equals(testContext.transferMe.getNodeRef()));
+ assertTrue("dest node ref does not exist", nodeService.exists(testContext.destNodeRef));
+
+ List tags = taggingService.getTags(testContext.contentNodeRef);
+
+ assertNotNull(tags);
+ assertTrue(tags.size() == 2);
+ assertTrue(tags.contains(TAG_1_NAME));
+ assertTrue(tags.contains(TAG_2_NAME));
+
+ return null;
+ }
+ };
+
+ tran.doInTransaction(validateStep2CB);
+
+ /**
+ * Step 3 - delete a tag
+ */
+
+ RetryingTransactionCallback deleteTagCB = new RetryingTransactionCallback() {
+
+ @Override
+ public Void execute() throws Throwable
+ {
+ taggingService.removeTag(testContext.contentNodeRef, TAG_2_NAME);
+ return null;
+ }
+ };
+
+ tran.doInTransaction(deleteTagCB);
+
+
+ logger.debug("Transfer again - this is to delete a tag");
+ tran.doInTransaction(transferCB);
+
+ // should probably be in contentModel
+ final QName ASPECT_GENERAL_CLASSIFIABLE = ContentModel.ASPECT_GEN_CLASSIFIABLE;
+
+ RetryingTransactionCallback validateStep3CB = new RetryingTransactionCallback() {
+
+ @Override
+ public Void execute() throws Throwable
+ {
+ assertFalse("unit test stuffed up - comparing with self", testContext.destNodeRef.equals(testContext.transferMe.getNodeRef()));
+ assertTrue("dest node ref does not exist", nodeService.exists(testContext.destNodeRef));
+
+ List tags = taggingService.getTags(testContext.destNodeRef);
+ assertNotNull(tags);
+ assertTrue(tags.size() == 1);
+ assertTrue(tags.contains(TAG_1_NAME));
+
+ return null;
+ }
+ };
+
+ tran.doInTransaction(validateStep3CB);
+
+ /**
+ * Step 4 - update to add a category that already exists
+ */
+ logger.debug("Step 4 - add a category");
+
+ RetryingTransactionCallback step4WriteContentCB = new RetryingTransactionCallback() {
+
+ @Override
+ public Void execute() throws Throwable
+ {
+ //
+ StoreRef workspaceSpacesStore = new StoreRef("workspace", "SpacesStore");
+ Collection rootCategories = categoryService.getRootCategories(workspaceSpacesStore, ASPECT_GENERAL_CLASSIFIABLE);
+
+ NodeRef languageCategory = null;
+ for (ChildAssociationRef ref : rootCategories)
+ {
+ if(ref.getQName().getLocalName().equalsIgnoreCase("LANGUAGES"))
+ {
+ languageCategory = ref.getChildRef();
+ }
+ }
+
+ assertNotNull("language category is null", languageCategory);
+
+ ChildAssociationRef categoryRef = categoryService.getCategory(languageCategory, ASPECT_GENERAL_CLASSIFIABLE, "English");
+
+ // Collection allCategories = categoryService.getCategories(workspaceSpacesStore, ASPECT_GENERAL_CLASSIFIABLE, Depth.ANY);
+
+ assertNotNull("ENGLISH CATEGORY REF is null", categoryRef);
+
+ List newCats = new ArrayList();
+ newCats.add(categoryRef.getChildRef());
+
+ nodeService.setProperty(testContext.contentNodeRef, ContentModel.PROP_CATEGORIES, (Serializable)newCats);
+
+ return null;
+ }
+ };
+
+ RetryingTransactionCallback validateStep4CB = new RetryingTransactionCallback() {
+
+ @Override
+ public Void execute() throws Throwable
+ {
+ assertFalse("unit test stuffed up - comparing with self", testContext.destNodeRef.equals(testContext.transferMe.getNodeRef()));
+ assertTrue("dest node ref does not exist", nodeService.exists(testContext.destNodeRef));
+
+ assertTrue("destination node is missing aspect general classifiable", nodeService.hasAspect(testContext.destNodeRef, ContentModel.ASPECT_GEN_CLASSIFIABLE));
+ Serializable categories = nodeService.getProperty(testContext.destNodeRef, ContentModel.PROP_CATEGORIES);
+ assertNotNull("categories is missing on destination node", categories);
+
+ return null;
+ }
+ };
+
+ tran.doInTransaction(step4WriteContentCB);
+
+ tran.doInTransaction(transferCB);
+
+ tran.doInTransaction(validateStep4CB);
+
+ } // testCategoriesAndTags
// Utility methods below.
private TransferTarget createTransferTarget(String name)
@@ -3495,5 +3775,5 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
when(descriptorService.getServerDescriptor()).thenReturn(serverDescriptor);
return descriptorService;
- }
+ }
}
diff --git a/source/test-java/org/alfresco/repo/transfer/UnitTestTransferManifestNodeFactory.java b/source/test-java/org/alfresco/repo/transfer/UnitTestTransferManifestNodeFactory.java
index 739a8764a5..15605452e0 100644
--- a/source/test-java/org/alfresco/repo/transfer/UnitTestTransferManifestNodeFactory.java
+++ b/source/test-java/org/alfresco/repo/transfer/UnitTestTransferManifestNodeFactory.java
@@ -71,14 +71,14 @@ public class UnitTestTransferManifestNodeFactory implements TransferManifestNode
this.realFactory = realFactory;
}
- public TransferManifestNode createTransferManifestNode(NodeRef nodeRef, TransferDefinition definition)
+ public TransferManifestNode createTransferManifestNode(NodeRef nodeRef, TransferDefinition definition, TransferContext transferContext)
{
- return createTransferManifestNode(nodeRef, definition, false);
+ return createTransferManifestNode(nodeRef, definition, transferContext, false);
}
- public TransferManifestNode createTransferManifestNode(NodeRef nodeRef, TransferDefinition definition, boolean forceDelete)
+ public TransferManifestNode createTransferManifestNode(NodeRef nodeRef, TransferDefinition definition, TransferContext transferContext, boolean forceDelete)
{
- TransferManifestNode newNode = realFactory.createTransferManifestNode(nodeRef, definition);
+ TransferManifestNode newNode = realFactory.createTransferManifestNode(nodeRef, definition, transferContext);
NodeRef origNodeRef = newNode.getNodeRef();
diff --git a/source/test-java/org/alfresco/repo/transfer/manifest/ManifestIntegrationTest.java b/source/test-java/org/alfresco/repo/transfer/manifest/ManifestIntegrationTest.java
index e8b9187447..9d922af9eb 100644
--- a/source/test-java/org/alfresco/repo/transfer/manifest/ManifestIntegrationTest.java
+++ b/source/test-java/org/alfresco/repo/transfer/manifest/ManifestIntegrationTest.java
@@ -36,6 +36,7 @@ import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.alfresco.model.ContentModel;
+import org.alfresco.repo.transfer.TransferContext;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
@@ -157,7 +158,7 @@ public class ManifestIntegrationTest extends BaseAlfrescoSpringTest
formatter.writeTransferManifestHeader(header);
for(NodeRef nodeRef : nodes)
{
- TransferManifestNode node = nodeFactory.createTransferManifestNode(nodeRef, null);
+ TransferManifestNode node = nodeFactory.createTransferManifestNode(nodeRef, null, new TransferContext());
formatter.writeTransferManifestNode(node);
sentNodes.put(nodeRef, node);
}